`
ch_kexin
  • 浏览: 898048 次
  • 性别: Icon_minigender_2
  • 来自: 青岛
社区版块
存档分类
最新评论

java NIO非阻塞方式的Socket编程 .

 
阅读更多

1.非阻塞方式的Socket编程:

传统阻塞方式的Socket编程,在读取或者写入数据时,TCP程序会阻塞直到客户端和服务端成功连接,UDP程序会阻塞直到读取到数据或写入数据。阻塞方式会影响程序性能,JDK5之后的NIO引入了非阻塞方式的Socket编程,非阻塞方式的Socket编程主要是使用Socket通道和Selector通道选择器,将Socket通道注册到通道选择器上,通过通道选择器选择通道已经准备好的事件的进行相应操作。

NIO socket简单例子如下:

import java.net.*;
import java.nio.channels.*;
import java.util.*;
import java.io.*;

public class NIOSocket{
	private static final int CLINET_PORT = 10200;
	private static final int SEVER_PORT = 10201;
	//面向流的连接套接字的可选择通道
	private SocketChannel ch;
	//通道选择器
	private Selector sel;
	public static void main(String[] args) throws IOException{
		//打开套接字通道
ch = SocketChannel.open();
//打开一个选择器
sel = Selector.open();	
try{
	//获取与套接字通道关联的套接字,并将该套接字绑定到本机指定端口
		ch.socket().bind(new InetSocketAddress(CLINET_PORT));
		//调整此通道为非阻塞模式
		ch.configureBlocking(false);
		//为通道选择器注册通道,并指定操作的选择键集
		ch.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE |
 SelectionKey.OP_CONNECT);
			//选择通道上注册的事件,其相应通道已为I/O操作准备就绪
			sel.select();
			//返回选择器的已选择键集
			Iterator it = sel.selectedKeys().iterator();
			while(it.hasNext()){
				//获取通道的选择器的键
	SelectionKey key = (SelectionKey)it.next();
	it.remove();
	//如果该通道已经准备好套接字连接
	if(key.isConnectable()){
	InetAddress addr = InetAddress.getLocalHost();
	System.out.println(“Connect will not block”);
//调用此方法发起一个非阻塞的连接操作,如果立即建立连接,则此方法//返回true.否则返回false,且必须在以后使用finishConnect()完成连接操作
//此处建立和服务端的Socket连接
	if(!ch.connect(new InetSocketAddress(addr, SEVER_PORT))){
		//完成非立即连接操作
	ch.finishConnect();
}
}
//此通道已准备好进行读取
if(key.isReadable()){
	System.out.println(“Read will not block”);
}
//此通道已准备好进行写入
if(key.isWritable()){
	System.out.println(“Write will not block”);
}
}
} finally{
ch.close();
sel.close();	
}
}
}

 

NIO Socket编程中有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的套接字通道socketchannel注册到Selector,程序不用阻塞等待,可以并行做别的事情,当有事件发生时,Selector会通知程序,传回一组SelectionKey,程序读取这些Key,就会获得注册过的socketchannel,然后,从这个Channel中读取和处理数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

2.使用NIO非阻塞方式Socket实现服务端和客户端程序:

通过下面一个简单的客户端/服务端程序说明一下NIO socket的基本API和步骤。

(1).服务端程序:

import java.net.*;
import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class NIOSocketServer{
	public static final int PORT = 8080;
	public static void main(String[] args)throws IOException{
		//NIO的通道channel中内容读取到字节缓冲区ByteBuffer时是字节方式存储的,
		//对于以字符方式读取和处理的数据必须要进行字符集编码和解码
	String encoding = System.getProperty(“file.encoding”);
	//加载字节编码集
	Charset cs = Charset.forName(encoding);
	//分配两个字节大小的字节缓冲区
	ByteBuffer buffer = ByteBuffer.allocate(16);
	SocketChannel ch = null;
	//打开服务端的套接字通道
	ServerSocketChannel ssc = ServerSocketChannel.open();
	//打开通道选择器
	Selector sel = Selector.open();
	try{
		//将服务端套接字通道连接方式调整为非阻塞模式
	ssc.configureBlocking(false);
	//将服务端套接字通道绑定到本机服务端端口
	ssc.socket().bind(new InetSocketAddress(PORT));
	//将服务端套接字通道OP_ACCEP事件注册到通道选择器上
	SelectionKey key = ssc.register(sel, SelectionKey.OP_ACCEPT);
	System.out.println(“Server on port:” + PORT);
	while(true){
		//通道选择器开始轮询通道事件
	sel.select();
	Iterator it = sel.selectedKeys().iterator();
	While(it.hasNext()){
		//获取通道选择器事件键
	SelectionKey skey = (SelectionKey)it.next();
	it.remove();
//服务端套接字通道发送客户端连接事件,客户端套接字通道尚未连接
	if(skey.isAcceptable()){
		//获取服务端套接字通道上连接的客户端套接字通道
	ch = ssc.accept();
	System.out.println(“Accepted connection from:” + ch.socket());
	//将客户端套接字通过连接模式调整为非阻塞模式
	ch.configureBlocking(false);
	//将客户端套接字通道OP_READ事件注册到通道选择器上
	ch.register(sel, SelectionKey.OP_READ);
}
//客户端套接字通道已经连接
else{
	//获取创建此通道选择器事件键的套接字通道
	ch = (SocketChannel)skey.channel();
	//将客户端套接字通道数据读取到字节缓冲区中
	ch.read(buffer);
	//使用字符集解码字节缓冲区数据
	CharBuffer cb = cs.decode((ByteBuffer)buffer.flip());
	String response = cb.toString();
	System.out.println(“Echoing:” + response) ;
	//重绕字节缓冲区,继续读取客户端套接字通道数据
	ch.write((ByteBuffer)buffer.rewind());
	if(response.indexOf(“END”) != -1) ch.close();
	buffer.clear();
}
}
}
}finally{
	if(ch != null) ch.close();
	ssc.close();
	sel.close();
}
}
}

 

(2).客户端程序:

import java.net.*;
import java.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class NIOSocketClient{
	private static final int CLIENT_PORT = 10200;
	public static void main(String[] args) throws IOException{
		SocketChannel sc = SocketChannel.open();
		Selector sel = Selector.open();
		try{
	sc.configureBlocking(false);
	sc.socket.bind(new InetSocketAddress(CLIENT_PORT));
	sc.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE
| SelectionKey.OP_CONNECT);
			int i = 0;
			boolean written = false;
			boolean done = false;
			String encoding = System.getProperty(“file.encoding”);
			Charset cs = Charset.forName(encoding);
			ByteBuffer buf = ByteBuffer.allocate(16);
			while(!done){
	sel.select();
	Iterator it = sel.selectedKeys().iterator();
	while(it.hasNext()){
	SelectionKey key = (SelectionKey)it.next();
	It.remove();
	//获取创建通道选择器事件键的套接字通道
	sc = (SocketChannel)key.channel();
	//当前通道选择器产生连接已经准备就绪事件,并且客户端套接字
//通道尚未连接到服务端套接字通道
	if(key.isConnectable() && !sc.isConnected()){
	InetAddress addr = InetAddress.getByName(null);
	//客户端套接字通道向服务端套接字通道发起非阻塞连接
	boolean success = sc.connect(new InetSocketAddress(
addr, NIOSocketServer.PORT));
					//如果客户端没有立即连接到服务端,则客户端完成非立即连接操作
						if(!success) sc.finishConnect();
}
//如果通道选择器产生读取操作已准备好事件,且已经向通道写入数据
if(key.isReadable() && written){
	if(sc.read((ByteBuffer)buf.clear()) > 0){
	written = false;
	//从套接字通道中读取数据
	String response = cs.decode((ByteBuffer)buf.flip()).toString();
	System.out.println(response);
	if(response.indexOf(“END”) != -1) done = true;
}
}
//如果通道选择器产生写入操作已准备好事件,并且尚未想通道写入数据
if(key.isWritable() && !written){
	//向套接字通道中写入数据
	if(i < 10) sc.write(ByteBuffer.wrap(new String(“howdy ” + i +
 ‘\n’).getBytes()));
else if(i == 10)sc.write(ByteBuffer.wrap(newString(“END”).
getBytes()));
						written = true;
						i++;
}
}
}
}finally{
	sc.close();
	sel.close();
}
}
}

 

分享到:
评论

相关推荐

    nio.rar_NIO_NIO-socket_java nio_java 实例_java.nio

    Java NIO(New IO)是Java 1.4版本引入的一个新特性,它为Java应用程序提供了非阻塞I/O操作的能力,与传统的IO模型(基于流的I/O和基于缓冲区的I/O)相比,NIO具有更高的效率和灵活性。在Java NIO中,数据是以通道...

    Java NIO Socket基本

    Java NIO的主要优势在于非阻塞特性。在BIO中,如果一个线程正在读取或写入数据,那么这个线程将被阻塞,直到I/O操作完成。而在NIO中,当数据未准备就绪时,线程不会被阻塞,而是返回到选择器,等待其他通道的事件。 ...

    基于NIO非阻塞的java聊天demo(支持单聊和群聊)

    在这个基于NIO非阻塞的Java聊天demo中,我们将会看到如何利用NIO实现一个支持单聊和群聊的应用。 首先,NIO的核心组件包括Channel、Buffer、Selector和Pipe。在传统的IO模型中,数据是从流的一端流向另一端,而在...

    java nio 实现socket

    **NIO非阻塞模式**:相比之下,NIO采用了非阻塞模式,即当没有数据可读时,`read()`方法不会阻塞,而是立即返回。这意味着应用程序可以同时处理多个输入/输出操作,而不需要为每个操作分配一个独立的线程。这样的...

    Java TCP_IP Socket编程.rar

    压缩包中的"Java TCP/IP Socket编程.pdf"很可能是详细的教程或示例代码,包括如何创建简单的聊天服务器或文件传输应用等。 总的来说,Java TCP/IP Socket编程涉及网络编程的基本原理和Java API的使用,是开发分布式...

    《NIO与Socket编程技术指南》_高洪岩

    Java NIO,自Java 1.4版本引入,是一种非阻塞I/O模型,相较于传统的BIO( Blocking I/O)模型,它提供了更高的性能和更灵活的编程方式。NIO的核心组件包括选择器(Selector)、通道(Channel)和缓冲区(Buffer)。...

    三步学会Java Socket编程.doc

    在实际应用中,可能会涉及到多线程处理多个客户端连接,或者使用更高级的I/O模型如NIO(非阻塞I/O)来提高性能。此外,异常处理是必不可少的,确保在网络通信过程中能正确处理各种可能出现的问题。 通过以上步骤,...

    java基于nio的socket通信.rar

    Java NIO(New IO)是Java 1.4版本引入的一个新特性,它为Java提供了非阻塞I/O操作的能力,极大地提升了Java在处理网络通信和文件读写时的性能。Socket通信是网络编程的基本元素,它允许两台计算机通过TCP/IP协议...

    使用NIO实现非阻塞socket通信

    在Java编程中,NIO(New ...总之,本项目通过Java NIO实现了非阻塞socket通信,有效地解决了高并发场景下的连接管理问题,提高了系统效率。对于学习和理解NIO以及如何构建基于NIO的网络应用,这是一个很好的实践案例。

    Socket中InputStream的read方法的阻塞特性

    2. **非阻塞I/O**:Java NIO(New IO)提供了非阻塞I/O操作,通过选择器(Selector)可以在数据准备就绪时进行读取,而不会浪费CPU资源在无谓的等待上。 3. **缓冲区管理**:合理使用缓冲区可以减少`read`方法的...

    nio.rar_Java socketA_java nio_java socket a

    在Java Socket编程中,NIO可以提供更高效、更灵活的网络通信方式,尤其适用于高并发的服务器应用。 标题中的“Java socketA_java nio_java socket a”可能是指使用Java NIO实现的Socket通信,这里的"A"可能是表示...

    基于java NIO的socket通信demo

    总的来说,这个示例展示了如何使用Java NIO进行Socket通信,通过非阻塞的方式提高系统的并发处理能力。同时,它还演示了如何处理字符集问题,保证了跨平台数据交换的准确性。对于理解和实践Java NIO在网络编程中的...

    基于Java NIO的网络编程框架.zip

    本项目深入探讨了Java网络编程中的多种模式,包括BIO(阻塞IO)、NIO(非阻塞IO)、IO多路复用(select、poll、epoll)、Reactor模式,以及零拷贝技术。通过这些实现,项目展示了如何在高并发环境下优化网络通信效率...

    Java Socket学习---nio实现阻塞多线程通信

    本篇文章将深入探讨如何使用Java NIO(非阻塞I/O)来实现阻塞多线程通信,这对于高性能服务器端应用尤其重要。我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 ...

    java的Socket编程

    - NIO(非阻塞I/O)的`java.nio`包提供了更高效的Socket编程模型,适用于高并发场景。 总之,Java的Socket编程提供了强大的能力来构建网络应用程序。通过理解`Socket`和`ServerSocket`类,以及如何使用它们进行...

Global site tag (gtag.js) - Google Analytics