`

[java]NIO服务器(ServerSocketChannel)开发的两种实现方式

 
阅读更多

内容还是NIO 而并不是NIO.2 算是对所学的一些总结.

在NIO中 开发TCP程序时会将SocketChannel的OP_READ注册到一个Selector上 selector进行轮训 这是与以往的Socket编程完全不同的新(现在看来已经不能算新啦)的东西.

 

ServerSocketChannel和原先的ServerSocket相比 增加了一个非堵塞的accept方式(configureBlocking(false)) 和传统的ServerSocket相比 设置成非堵塞方式accept方法会立即返回(没有连接到来就返回null) 所以和SocketChannel一样 他也需要注册到一个Selector上 注册的方法选为OP_ACCEPT.

 

现在来看看 ServerSocketChannel设置为堵塞(默认)和非堵塞的实现上的区别 以下的图当做草图来用...因为本人不会画uml...画出来多半也是错的 错的地方欢迎打脸..:

 

非堵塞情况下:



 这种情况比较简单  ServerSocketChannel在运行前设置成非堵塞模式 然后注册到实际进行任务处理的Dispather线程的Selector中就可以了

代码如下:

 

	public void start() throws IOException{
		ServerSocketChannel ssc=ServerSocketChannel.open();
		// 设置端口绑定
		ssc.socket().bind(new InetSocketAddress(port));
		// 设置地址复用
		ssc.socket().setReuseAddress(true);
		ssc.configureBlocking(false); 
		Dispatcher dispatcher=new NIODispatcher();
		dispatcher.register(ssc, SelectionKey.OP_ACCEPT);
		new Thread(dispatcher).start();
	}

 对应的dispatcher中的Selector的轮询操作要麻烦一点 因为要判断是Accept的操作 还是Read的操作

 

 Dispatcher中的主要代码如下:

 

	@Override
	public void run() {
		while (true) {
			try {
				dispatch();
			} catch (IOException e) {
				System.out.println(e);
				logger.error("NIODispatcher run()", e);
			}
		}
	}

	private void dispatch() throws IOException {
		selector.select();
		for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor
				.hasNext();) {
			SelectionKey sk = itor.next();
			itor.remove();
			if (sk.isAcceptable()) {
				ServerSocketChannel serverSocketChannel = (ServerSocketChannel) sk
						.channel();
				SocketChannel sc = serverSocketChannel.accept();
				sc.configureBlocking(false);

				// 立即注册一个 OP_READ 的SelectionKey, 接收客户端的消息
				SelectionKey key = sc.register(selector, SelectionKey.OP_READ);
				// 如果socket没有连接打开或者sk无效那么下一个
			} else if (sk.isReadable()) {
				SocketChannel sc = (SocketChannel) sk.channel();
				ChannelHelper ch = new ChannelHelper(sc, false);
				try {
					int count = ch.read();
					// 小于零 意味着要么就是传过来的没有信息 要么就是有异常了
					if (count < 0) {
						sk.cancel();
						sc.close();
						continue;
					}
					// 等于零的情况 继续
					if (count <= 0) {
						sk.cancel();
						sc.close();
						continue;
					}
				} catch (Exception e) {
					logger.error("NIODiapatcher dispatch()", e);
					sk.cancel();
					sc.close();
					continue;
				}
				RequestHandler handler = new RequestHandler(ch, sk);
				pool.execute(handler);
			}
		}
	}

	public void register(ServerSocketChannel ssc, int ops) {
		try {
			ssc.register(selector, ops);
		} catch (ClosedChannelException e) {
			logger.error("NIODispatcher register", e);
		}
	}

 

 

 

以上是非堵塞的实现方式

堵塞的话要多一个接受者的线程来处理到来的连接 并把连接注册到Dispatcher线程的Selector中

堵塞的情况:

图示:



 额 图示上都没画箭头 箭头方向是NIO到acceptor和dispatcher  acceptor到dispatcher dispatcher负责处理任务(更确切的说是负责任务的派遣)

 

代码如下:

NIOServer中 不用设置阻塞模式 默认为阻塞:

 

	public void start() throws IOException{
		ServerSocketChannel ssc=ServerSocketChannel.open();
		// 设置端口绑定
		ssc.socket().bind(new InetSocketAddress(port));
		// 设置地址复用
		ssc.socket().setReuseAddress(true);
		
		Dispatcher dispatcher=new NIODispatcher();
		
		Acceptor acceptor=new NIOAcceptor(ssc, dispatcher);
		
		new Thread(acceptor).start();
		new Thread(dispatcher).start();
	}

 这里可以看到多了一个Acceptor线程

 

这个线程的内容很简单 就是负责把得到的连接注册到dispatcher上:

 

	@Override
	public void run() {
		while(true){
			try {
				SocketChannel sc=ssc.accept();
				sc.configureBlocking(false);
				dispatcher.register(sc, SelectionKey.OP_READ);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

 最后是dispatcher的代码:

 

 

public class NIODispatcher implements Dispatcher {

	private static final LogUtil logger = new LogUtil(NIODispatcher.class);

	private ReentrantLock lock = new ReentrantLock();

	private Selector selector = null;

	private ExecutorService pool=null;
	
	public NIODispatcher() throws IOException {
		selector = Selector.open();
		pool=Executors.newCachedThreadPool();
	}

	@Override
	public void run() {
		while (true) {
			try {
				dispatch();
			} catch (IOException e) {
				System.out.println(e);
				logger.error("NIODispatcher run()", e);
			}
		}
	}

	private void dispatch() throws IOException {
		System.out.println("---select操作----");
		selector.select();
		for (Iterator<SelectionKey> itor = selector.selectedKeys().iterator(); itor
				.hasNext();) {
			SelectionKey sk = itor.next();
			itor.remove();
			SocketChannel sc = (SocketChannel) sk.channel();
			// 如果socket没有连接打开或者sk无效那么下一个
			System.out.println("---"+sc.getLocalAddress()+" ---");
			if (sc.socket().isClosed()|| !sk.isValid() || !sc.isOpen()) {
				System.out.println("连接无效");
				sk.cancel();
				sc.close();
				continue;
			}

			ChannelHelper ch = new ChannelHelper(sc, false);
			try {
				int count = ch.read();
				//小于等于零 意味着要么就是传过来的没有信息 要么就是有异常了
				// 而在读取中做了处理 如果返回是0就是没有信息了 可以安心关闭连接
				if (count <= 0) {
					sk.cancel();
					sc.close();
					continue;
				}
			} catch (Exception e) {
				logger.error("NIODiapatcher dispatch()", e);
				sk.cancel();
				sc.close();
				continue;
			}
			RequestHandler handler=new RequestHandler(ch, sk);
			pool.execute(handler);

		}
		lock.lock();
		lock.unlock();
	}

	@Override
	public void register(SocketChannel sc, int ops) {
		try {
			lock.lock();
			selector.wakeup();
			sc.register(selector, ops);
		} catch (Exception ex) {
			logger.error("NIODispatcher register", ex);
		} finally {
			lock.unlock();
		}
	}

}

 注意注册的时候要先让Selector wakeup一下 这是为了让在select()方法中堵塞的seletor能去做其他的事情(这里就是SocketChannel注册咯)

 

更多关于wakeup的解释看:http://www.iteye.com/topic/650195

  • 大小: 3.5 KB
  • 大小: 7.9 KB
0
5
分享到:
评论
1 楼 tmartin 2013-09-12  
不错

相关推荐

    Java NIO服务器端开发详解

    Java NIO 服务器端开发是 Java 语言中的一种高性能的 I/O 模式,提供了非阻塞式的 I/O 操作,能够提高服务器端的性能和可扩展性。下面是 Java NIO 服务器端开发的详细介绍: 一、NIO 类库简介 Java NIO 中的缓冲区...

    java NIO实例

    `NIOServer.java`和`NIOClient.java`这两个文件很可能是用于演示Java NIO服务器端和客户端的基本操作。下面将详细介绍Java NIO的主要组件和工作原理,并结合这两个文件名推测它们可能包含的内容。 1. **Selector...

    java NIO.zip

    Java NIO支持多种类型的通道,包括文件通道(FileChannel)、套接字通道(SocketChannel)和服务器套接字通道(ServerSocketChannel)等。通道可以同时进行读写操作,并且可以实现异步读写。 2. **缓冲区(Buffers...

    Java NIO英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据...

    Java NIO Socket基本

    NIO在Java 1.4版本引入,其设计目标是提供一种更高效、更灵活的I/O操作方式,特别适合处理大量并发连接的场景,如服务器端编程。在NIO中,我们不再像BIO那样等待一个操作完成,而是通过选择器(Selector)监控多个...

    一个java NIO的例子

    本例子中的"NioServer"可能是一个简单的Java NIO服务器端程序,用于演示如何使用NIO进行网络通信。下面我们将深入探讨Java NIO的关键组件和工作原理。 1. **通道(Channel)**:通道是数据传输的途径,类似于传统的...

    Java NIO 中英文版

    - Java NIO通过非阻塞的方式和选择器,使得处理大量并发连接变得更加高效,尤其适合服务器端的高并发场景。 综上所述,Java NIO是一个强大的I/O库,它为开发者提供了更高效、灵活的I/O操作,特别是在处理高并发、...

    Java NIO 在并发型服务器设计中的应用

    在NIO中,有多种类型的通道,例如 `ServerSocketChannel` 和 `SocketChannel`,它们都是 `SelectableChannel` 的子类,支持同步和异步两种工作模式。 - **Selector(选择器)**:Selector 是NIO的关键组件之一,它...

    java nio

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种I/O模型,旨在提供一种更高效、更具弹性的I/O处理方式。NIO与传统的BIO(Blocking I/O)模式相比,主要区别在于对I/O...

    java-instantcode-developing.rar_java nio

    7. **管道(Pipe)**:管道是Java NIO中用于线程间通信的一种机制,它允许两个线程之间通过管道进行单向数据传输。 8. **字符集转换**:Java NIO提供Charset类和CharsetDecoder/CharsetEncoder类,支持多种字符集的...

    JAVA NIO 异步通信模板服务端

    本模板服务端就是基于JAVA NIO实现的异步通信机制,它能够高效地处理多个客户端连接,并且通过非阻塞I/O模式提高服务器的性能。 ### NIO核心组件 1. **Channel(通道)**:与传统I/O中的流不同,NIO中的Channel是...

    java NIO socket聊天

    Java NIO(Non-blocking Input/Output)是一种在Java中实现高效网络编程的机制,相比于传统的BIO(Blocking I/O),NIO提供了更好的并发性能。在Java NIO中,服务器端可以使用一个线程来处理多个客户端连接,这被...

    《Java NIO》Download Url

    《Java NIO》这本书主要探讨的是Java的非阻塞I/O模型,它是Java标准库提供的一种高效、低延迟的I/O处理方式。NIO代表Non-blocking Input/Output,与传统的I/O模型(BIO,Blocking I/O)相比,NIO在处理大量并发连接...

    tcp.zip_java Tcp _java nio_java nio TCP_tcp_tcp java

    TCP(传输控制协议)是一种面向连接、可靠的、基于字节流的传输层通信协议,而NIO(非阻塞I/O)则是Java提供的一种高效处理I/O操作的方式。在这个“tcp.zip”压缩包中,我们可能找到了关于使用Java实现TCP服务器和...

    Java NIO系列教程

    Java NIO (New IO) 是从 Java 1.4 开始提供的一种新的 I/O 处理方式,旨在改进传统 Java IO API 的性能并引入更高效的数据处理机制。Java NIO 主要包括三大核心组成部分:Channels、Buffers 和 Selectors。 #### ...

    Java NIO非阻塞服务端与客户端相互通信

    Java NIO(New IO)是Java 1.4版本引入的一种新的IO模型,它提供了不同于传统阻塞IO的处理方式,极大地提高了IO操作的效率。非阻塞IO的核心在于,当数据不可用时,不会使线程等待,而是立即返回并进行其他操作,这样...

    java-nio.rar_NIO_java nio

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java从1.4版本开始引入的一种新的I/O模型,它为Java应用程序提供了更高效的数据传输方式。传统的Java IO基于流(Stream)和缓冲区(Buffer)进行...

    Java-NIO非阻塞服务器示例.docx

    ServerSocketChannel和SocketChannel是NIO包中的两个重要的Channel接口,分别用于服务器端和客户端的连接。ServerSocketChannel用于监听客户端的连接请求,而SocketChannel用于与客户端进行通信。 五、ByteBuffer...

    Java NIO 中文版.rar

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统I/O模型的新技术。在Java 1.4版本中引入,NIO为开发者提供了更加灵活和高效的I/O操作方式,特别是在处理高并发、大...

Global site tag (gtag.js) - Google Analytics