Java NIO通信的实现

来源:互联网 发布:淘宝网店费用 一年 编辑:程序博客网 时间:2024/05/20 18:17
非阻塞网络IO通信:
当客户端的通道(都注册在Selector中)准备就绪后,Selector才向服务端发送请求。服务端才分配线程执行请求(没准备好前服务端不会先分配线程阻塞等待客户端)。

阻塞式和非阻塞式IO区别:
        传统的 IO 流都是阻塞式的。当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
        Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端


1
package javanio;
2
3
import org.junit.Test;
4
5
import java.io.IOException;
6
import java.net.InetSocketAddress;
7
import java.nio.ByteBuffer;
8
import java.nio.channels.SelectionKey;
9
import java.nio.channels.Selector;
10
import java.nio.channels.ServerSocketChannel;
11
import java.nio.channels.SocketChannel;
12
import java.util.Date;
13
import java.util.Iterator;
14
15
/**
16
 * 非阻塞式IO
17
 */
18
public class TestNonBlockingNIO {
19
20
    //客户端
21
    @Test
22
    public void client()throws IOException{
23
        //1.获取通道
24
        SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",9898));
25
26
        //2.切换非阻塞模式
27
        sChannel.configureBlocking(false);
28
29
        //3.分配指定大小缓冲区
30
        ByteBuffer buf = ByteBuffer.allocate(1024);
31
32
        //4.发送数据给服务端
33
        buf.put(new Date().toString().getBytes());
34
        buf.flip();
35
        sChannel.write(buf);
36
        buf.clear();
37
38
        //5.关闭通道
39
        sChannel.close();
40
    }
41
42
    //服务端
43
    @Test
44
    public void server()throws IOException{
45
        //1.获取通道
46
        ServerSocketChannel ssChannel = ServerSocketChannel.open();
47
48
        //2.切换非阻塞模式
49
        ssChannel.configureBlocking(false);
50
51
        //3.绑定连接
52
        ssChannel.bind(new InetSocketAddress(9898));
53
54
        //4.获取选择器
55
        Selector selector = Selector.open();
56
57
        //5.将通道注册到选择器上,并指定监听事件
58
        ssChannel.register(selector, SelectionKey.OP_ACCEPT);
59
60
        //6.轮询式获取选择器的准备就绪事件
61
        while(selector.select() > 0){
62
            //7.获取当前选择器中所有注册的选择键(已就绪的监听事件)
63
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
64
            //8.获取准备就绪的事件
65
            while(iterator.hasNext()){
66
                SelectionKey sk = iterator.next();
67
                //9.判断什么事件准备就绪
68
                if (sk.isAcceptable()){
69
                    //10.获取客户端连接
70
                    SocketChannel sChannel = ssChannel.accept();
71
                    //11.切换非阻塞模式
72
                    sChannel.configureBlocking(false);
73
                    //12.将该通道注册到选择器上
74
                    sChannel.register(selector,SelectionKey.OP_READ);
75
                }else if(sk.isReadable()){//读就绪
76
                    //13.获取当前选择器上读就绪状态的通道
77
                    SocketChannel sChannel = (SocketChannel) sk.channel();
78
79
                    //14.读取数据
80
                    ByteBuffer buf = ByteBuffer.allocate(1024);
81
82
                    int len = 0;
83
                    while ((len=sChannel.read(buf))>0){
84
                        buf.flip();
85
                        System.out.println(new String(buf.array(),0,len));
86
                        buf.clear();
87
                    }
88
                }
89
                //15.取消选择键
90
                iterator.remove();
91
            }
92
        }
93
94
    }
95
}
96

 
 
原创粉丝点击