NIO 实现 IO 多路复用,不用再为每个 IO 链接创建一个进程。
来看一下 Server 和 Client 端创建一个 NIO 连接并通信时各自需要做的步骤。
Server 端:
1. 创建 NIO channels,由于是服务器端,用的是 ServerSocketChannel。
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
这样创建一个 ServerSocketChannel 对象,并设置 blocking 属性。
NIO Channel 有很多种,但先不在这里一一解释。NIO channels 种类有:
java.nio.channels.Channel java.nio.channels.FileChannel java.nio.channels.SocketChannel java.nio.channels.ServerSocketChannel
2. 利用 ServerSocketChannel.socket() 方法获取一个 ServerSocket。然后用 bind 方法绑定服务器地址给 SocketServer。
- ServerSocket serverSocket = serverSocketChannel.socket();
- serverSocket.bind(new InetSocketAddress(port));
这一步之后 ServerSocketChannel 就已经有了自己的 ServerSocket 了
3. 还需要把一个 selector 注册到 ServerSocketChannel 中去
- Selector selector = Selector.open();
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //OP_ACCEPT这个表示对接收连接感兴趣。
这里的 SelectionKey 表示 Selector 和被注册的 channel 之间关系,一份凭证。SelectionKey 保存 channel 感兴趣的事件。
4.Selector.select() 阻塞等待。有消息的话,就更新所有 SelectionKey 的状态。
- selector.select(); //等待有状态变更Set selectionKeys = selector.selectedKeys();//已经更新了selector里边的所有SelectionKey。这里返回其集合,并利用下面的迭代器轮询所有更新的SelectionKey。Iterator iterator = selectionKeys.iterator();
5.
- while (iterator.hasNext()) {
- SelectionKey selectionKey = iterator.next(); //提取已经被更新的SelectionKey iterator.remove();//这里将上面返回的SelectionKey从迭代器中删除!!不删除下次取出来还是这个~~ if (selectionKey.isAcceptable()) {//看这个SelectionKey的时间是不是OP_ACCEPT。Client第一次连接就会是OP_ACCEPT。 System.out.println("Server: selectionKey isAcceptable"); server = (ServerSocketChannel) selectionKey.channel();//这个ServerSocketChannel就是上面定义的serverSocketChannel。其实可以用一个类成员,就不用这样重新取出来了。 client = server.accept(); //ServerSocketChannel接收一个连接,并返回一个SocketChannel。不管有多少个连接过来,Server这边都只有一个SocketChannel!!。我们需要把这个SocketChannel重新注册到selector中,用这个检查READ事件。所以这里很清楚了,就是ServerSocketChannel只用来检查是否有Client连接来。来了之后就从accetp获得一个SocketChannel重新注册给selector。然后在这里检查是否有字符发过来!!。 client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ);//注册连接的SocketChannel给selector,检查是否有发过来东西。 } else if (selectionKey.isReadable()) { System.out.println("Server: selectionKey isReadable"); client = (SocketChannel) selectionKey.channel(); receivebuffer.clear();//receivebuffer是ByteBuffer.allocate(2048)分配的一个接收用的buffer int count = client.read(receivebuffer); receiveText = new String( receivebuffer.array(),0,count); System.out.println("服务器端接受客户端数据--:"+receiveText); } else if (selectionKey.isWritable()) { System.out.println("Server: selectionKey isWritable"); }}
Client 端:
1. 初始化一个 SocketChannel,设置 block 属性等。这个和服务器端的第一步对应。
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.configureBlocking(false);
2. 初始化一个 selector,并注册 SocketChannel。这个和服务器的第三步对应
- Selector selector = Selector.open();
- socketChannel.register(selector, SelectionKey.OP_CONNECT);
3. 连接服务器。
- InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("localhost", 8080);
- socketChannel.connect(SERVER_ADDRESS); //这个和服务器端serverSocketChannel.socket()来获取serversocket以及bind相对应。没有这个就不能有连接
4.
- selector.select();
- Set selectionKeys;
- Iterator iterator;
- selectionKeys = selector.selectedKeys();
- iterator = selectionKeys.iterator();
5.
- while (iterator.hasNext()) {
- selectionKey = iterator.next();
- if (selectionKey.isConnectable()) {
- System.out.println("Client:selectionKey isConnectable");
- client = (SocketChannel) selectionKey.channel(); // 判断此通道上是否正在进行连接操作。 // 完成套接字通道的连接过程. if (client.isConnectionPending()) { client.finishConnect(); System.out.println("完成连接!"); } client.register(selector, SelectionKey.OP_WRITE); } else if (selectionKey.isReadable()) { System.out.println("Client:selectionKey isReadable"); } else if (selectionKey.isWritable()) { sendbuffer.clear(); client = (SocketChannel) selectionKey.channel(); readbuffer = in.readLine(); sendbuffer.put(readbuffer.getBytes()); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 sendbuffer.flip(); client.write(sendbuffer); System.out.println("客户端向服务器端发送数据--:"+readbuffer); //client.register(selector, SelectionKey.OP_READ); }}
例子
Server 端:
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.net.ServerSocket;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.ServerSocketChannel;
- import java.nio.channels.SocketChannel;
- import java.util.Iterator;
- import java.util.Set;
- public class java_nio_keyinputtransmit_server {
- private Selector selector;
- private int BLOCK = 4096;
- private ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
- private ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
- public java_nio_keyinputtransmit_server(int port) throws IOException {
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- ServerSocket serverSocket = serverSocketChannel.socket();
- serverSocket.bind(new InetSocketAddress(port));
- selector = Selector.open();
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- System.out.println("Server Start----8080:");
- }
- private void listen() throws IOException {
- System.out.println("Server: listen started");
- ServerSocketChannel server = null;
- SocketChannel client = null;
- String receiveText;
- String sendText;
- while (true) {
- selector.select();
- System.out.println("Server: lisen selector");
- Set selectionKeys = selector.selectedKeys();
- Iterator iterator = selectionKeys.iterator();
- while (iterator.hasNext()) {
- SelectionKey selectionKey = iterator.next();
- iterator.remove();
- if (selectionKey.isAcceptable()) {
- System.out.println("Server: selectionKey isAcceptable");
- server = (ServerSocketChannel) selectionKey.channel();
- client = server.accept();
- client.configureBlocking(false);
- client.register(selector, SelectionKey.OP_READ);
- } else if (selectionKey.isReadable()) {
- System.out.println("Server: selectionKey isReadable");
- client = (SocketChannel) selectionKey.channel();
- receivebuffer.clear();
- int count = client.read(receivebuffer);
- receiveText = new String(receivebuffer.array(), 0, count);
- System.out.println("服务器端接受客户端数据--:" + receiveText); //client.register(selector, SelectionKey.OP_WRITE); } else if (selectionKey.isWritable()) { System.out.println("Server: selectionKey isWritable"); } //handleKey(selectionKey); } } } public static void main(String args[]) throws IOException { int port = 8080; java_nio_keyinputtransmit_server server = new java_nio_keyinputtransmit_server(port); server.listen(); }}
Client 端
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.InetSocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.SocketChannel;
- import java.util.Iterator;
- import java.util.Set;
- public class java_nio_keyinputtransmit_client {
- private static int flag = 0;
- private static int BLOCK = 4096;
- private static ByteBuffer sendbuffer = ByteBuffer.allocate(BLOCK);
- private static ByteBuffer receivebuffer = ByteBuffer.allocate(BLOCK);
- private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("localhost", 8080);
- public static void main(String args[]) throws IOException {
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.configureBlocking(false);
- Selector selector = Selector.open();
- socketChannel.register(selector, SelectionKey.OP_CONNECT);
- socketChannel.connect(SERVER_ADDRESS); //连接之后,服务期select.selector()阻塞解除,开始下面的流程 BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String readbuffer = null; //readbuffer = in.readLine(); //while(!readbuffer.equals("END")){ while(true) { //System.out.println("readbuffer is "+readbuffer ); //System.out.println("Client:selector select begin"); selector.select(); //System.out.println("Client:selector select end"); Set selectionKeys; Iterator iterator; SelectionKey selectionKey; SocketChannel client; String receiveText; String sendText; selectionKeys = selector.selectedKeys(); iterator = selectionKeys.iterator(); while (iterator.hasNext()) { selectionKey = iterator.next(); if (selectionKey.isConnectable()) { System.out.println("Client:selectionKey isConnectable"); client = (SocketChannel) selectionKey.channel(); // 判断此通道上是否正在进行连接操作。 // 完成套接字通道的连接过程。 if (client.isConnectionPending()) { client.finishConnect(); System.out.println("完成连接!"); sendbuffer.clear(); sendbuffer.put("Hello,Server".getBytes()); sendbuffer.flip(); client.write(sendbuffer); } client.register(selector, SelectionKey.OP_WRITE); } else if (selectionKey.isReadable()) { System.out.println("Client:selectionKey isReadable"); } else if (selectionKey.isWritable()) { sendbuffer.clear(); client = (SocketChannel) selectionKey.channel(); readbuffer = in.readLine(); sendbuffer.put(readbuffer.getBytes()); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 sendbuffer.flip(); client.write(sendbuffer); System.out.println("客户端向服务器端发送数据--:"+readbuffer); //client.register(selector, SelectionKey.OP_READ); } } selectionKeys.clear(); //readbuffer = in.readLine(); } //System.out.println("Client End"); /*BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String readbuffer = null;try {readbuffer = in.readLine();System.out.println(readbuffer);while(!readbuffer.equals("END")) {readbuffer = in.readLine();System.out.println(readbuffer);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}*/ }}
Server 端的 log 输出
- Server Start----8080 : Server: listen startedServer: lisen selectorServer: selectionKey isAcceptableServer: lisen selectorServer: selectionKey isReadable服务器端接受客户端数据--:Hello,
- ServerServer: lisen selectorServer: selectionKey isReadable服务器端接受客户端数据--:agadsf
Client 端 log 输出
- Client:selectionKey isConnectable完成连接!agadsf客户端向服务器端发送数据--:agadsf
就爱阅读 www.92to.com 网友整理上传, 为您提供最全的知识大全, 期待您的分享,转载请注明出处。
来源: