Java : NIO

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<SelectionKey> selectionKeys = selector.selectedKeys();//已经更新了selector里边的所有SelectionKey。这里返回其集合,并利用下面的迭代器轮询所有更新的SelectionKey。
Iterator<SelectionKey> 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<SelectionKey> selectionKeys;  
Iterator<SelectionKey> 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<SelectionKey> selectionKeys = selector.selectedKeys();  
            Iterator<SelectionKey> 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<SelectionKey> selectionKeys;  
            Iterator<SelectionKey> 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 block
e.printStackTrace();
}*/
    }
}

Server端的log输出

Server Start----8080:
Server: listen started
Server: lisen selector
Server: selectionKey isAcceptable
Server: lisen selector
Server: selectionKey isReadable
服务器端接受客户端数据--:Hello,Server
Server: lisen selector
Server: selectionKey isReadable
服务器端接受客户端数据--:agadsf

Client端log输出

Client:selectionKey isConnectable
完成连接!
agadsf
客户端向服务器端发送数据--:agadsf
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值