Java Socket IO(BIO、NIO)

总结下Java socket IO。首先是各类IO的定义,这个定义彷佛也是众说纷纭。我按照stackoverflow上面的解释:java

IO有两种分法:按照阻塞或者按照同步。按照阻塞,有阻塞IO和非阻塞IO。按照同步就是同步IO或者异步IO。咱们能够认为阻塞IO和同步IO相等,而非阻塞IO和异步IO不一样。git

阻塞IO或者同步IO是指:IO的请求发出去以后,请求者一直在等待回复,当IO的数据回来到来以后,请求者就开始接受数据。阻塞的意思就是:IO请求发出去以后请求线程就中止在那里,一直等待数据到来。github

非阻塞则是:IO请求发出去以后,会马上收到回复,这个回复多是IO能够当即进行,或者是没法进行IO的错误。因此非阻塞IO请求者必须一直调用那个API,一直到API返回能够进行IO的信号。编程

 

异步IO:IO请求发出以后,后台会创建一个进程,处理IO,当IO都处理完以后,把处理完的数据交给IO的请求者。多线程

本文用Java socket实现阻塞和非阻塞IO(这里大部份内容都学习自千与的专栏,这是位大牛,竟然hadoop源码分析写了19篇博客)。而后本文章的全部代码我都放在Github上了。异步

阻塞IO

阻塞IO比较简单,就是用普通的socket去写,由于没有什么太复杂的处理。创建一个socket,而后,获取它的inputstream和outputstream,而后进行读写操做。socket

Server端主要代码,handleSocket就是从socket里面读取数据,而后向client写数据:async

	ServerSocket serverSocket = new ServerSocket(port); while (true) { socket = serverSocket.accept(); handleSocket(socket); }

Client只是简单的发送一句消息:oop

	socket = new Socket(host, port); out = socket.getOutputStream(); out.write(data); out.flush(); in = socket.getInputStream(); byte[] buffer = new byte[128]; int receivedBytes; if((receivedBytes = in.read(buffer))!=-1){ System.out.println("Client: received msg from server: " + new String(buffer, 0, receivedBytes)); }

同时client5000个,使用了大概5s。而后还可使用多线程Server,就是在每个client到的时候分配一个线程来处理这个IO,理论上能够增长效率,可是彷佛是由于每次处理时间过短,效果不明显。主要代码:源码分析

	boolean flag = false; int count = 0; ServerSocket serverSocket = new ServerSocket(port); Date start = null; while (true) { socket = serverSocket.accept(); if (!flag) { start = new Date(); flag = true; } pool.execute(new RequestHandler(socket)); if(++count== threadCount){ flag = false; Date end = new Date(); System.out.println(threadCount+" client requests spends: " + (end.getTime() -start.getTime())); } }

其中的pool是ExecutorService,提供线程池,而后RequestHandler是一个Runnable类,用来处理一个socket链接。简单讲来,就是把前面server处理socket的代码放到了这个handler里面。

NIO,非阻塞IO

我认定Java的NIO包实现的是同步非阻塞IO,也有人说不是,至少我这里这么认为。在server端,首先打开一个channel,而后向其中注册一个selector,这个selector会在channel中轮询注册的事件,而后根据事件的类型做出处理。通常事件的类型有Accept、read、write。

在Client端也能够是同样的注册,而后经过和server一样的处理方式处理事件(可是没有accept事件,由于只有server才能accept的)。可是个人例子里面只是简单的发送了一条消息。

Server的主要代码:

	Selector selector = Selector.open(); ServerSocketChannel serverSocketChannel = ServerSocketChannel .open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(address); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); log.info("Server: socket server started!"); while (true) { int nKeys = selector.select(); if (nKeys > 0) { Set selectedKeys = selector.selectedKeys(); Iterator it = selectedKeys.iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey) it.next(); if (key.isAcceptable()) { log.info("Server: Selection key is acceptable"); handler.handleAccept(key); } else if (key.isReadable()) { log.info("Server: Selection key is readable"); handler.handleRead(key); } else if (key.isWritable()) { log.info("Server: Selection key is writable"); handler.handleWrite(key); } it.remove(); } } }

其中的handler就是处理每种类型的事件的类,举个Read的例子:

public void handleRead(SelectionKey key) throws IOException { ByteBuffer byteBuffer = ByteBuffer.allocate(512); SocketChannel socketChannel = (SocketChannel) key .channel(); while (true) { int readBytes = socketChannel.read(byteBuffer); if (readBytes > 0) { log.info("Server: readBytes = " + readBytes); log.info("Server: data = " + new String(byteBuffer.array(), 0, readBytes)); byteBuffer.flip(); socketChannel.write(byteBuffer); break; } } socketChannel.close(); }

Client就比较简单了,就是用channel直接发送了一句消息:

public void send(String data) { try { SocketChannel socketChannel = SocketChannel.open(inetSocketAddress); socketChannel.configureBlocking(false); ByteBuffer byteBuffer = ByteBuffer.allocate(512); socketChannel.write(ByteBuffer.wrap(data.getBytes())); while (true) { byteBuffer.clear(); int readBytes = socketChannel.read(byteBuffer); if (readBytes > 0) { byteBuffer.flip(); log.info("Client: readBytes = " + readBytes); log.info("Client: data = " + byteBuffer.toString()); socketChannel.close(); break; } } } catch (IOException e) { e.printStackTrace(); } }

最后,这些Java的socket编程在实际工程中已经不多使用了,因为Unix的poll等功能的出现,select相比较之下,有点弱了。接下来能够考虑研究下。

NIO包的API介绍:

http://wufan0023.iteye.com/blog/198722

http://wufan0023.iteye.com/blog/198710

    分享到:

This entry was posted in Java topic and tagged Javasocket by 柳浪闻莺. Bookmark the permalink.

相关文章
相关标签/搜索