一、使用Java NIO完成网络通信的三个核心
1.通道(Channel):负责连接
java.nio.channels.Channel 接口:
|--SelectableChannel
|--SocketChannel
|--ServerSocketChannel
|--DatagramChannel
|--Pipe.SinkChannel
|--Pipe.SourceChannel
2.缓冲区(buffer):负责数据存取
3.选择器(Selector):是SelectableChannel 的多路复用器,用来检测SelectableChannel的IO状态
案例:使用非阻塞式实现简单的群聊天系统
一、实现客户端
1 public static void main(String[] args) throws Exception { 2 SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8989)); 3 4 //2. 切换非阻塞模式 5 sChannel.configureBlocking(false); 6 7 //3. 分配指定大小的缓冲区 8 ByteBuffer buf = ByteBuffer.allocate(1024); 9 10 //4. 发送数据给服务端 11 Scanner scan = new Scanner(System.in); 12 13 while (scan.hasNext()) { 14 String str = scan.next(); 15 buf.put((new Date().toString() + "\n" + str).getBytes()); 16 buf.flip(); 17 sChannel.write(buf); 18 buf.clear(); 19 } 20 21 //5. 关闭通道 22 sChannel.close(); 23 }
二、实现服务端
@Test public void server() { ServerSocketChannel ssChannel = null; try { ssChannel = ServerSocketChannel.open(); //配置非阻塞 ssChannel.configureBlocking(false); //绑定连接 ssChannel.bind(new InetSocketAddress(8989)); Selector selector = Selector.open(); //将通道注册到监听器中,并且制定监听器的监听模式为“接受” ssChannel.register(selector, SelectionKey.OP_ACCEPT); //轮询的选择已经就绪的事件 while (selector.select() > 0) { //获取当前监听 Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { //获取准备就绪的事件 SelectionKey sk = it.next(); if (sk.isAcceptable()) { //如果接受就绪,则获取客户端的连接 SocketChannel clientChannel = ssChannel.accept(); //同样配置成非阻塞式 clientChannel.configureBlocking(false); //把客户端的连接注册到选择器上 clientChannel.register(selector, SelectionKey.OP_READ); } else if (sk.isReadable()) { //如果读取就绪,则获取读取的通道 SocketChannel socketChannel = (SocketChannel) sk.channel(); //配置成非阻塞模式 socketChannel.configureBlocking(false); //读取数据 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); int len = 0; while ((len = socketChannel.read(byteBuffer)) > 0) { byteBuffer.flip(); System.out.println(new String(byteBuffer.array(), 0, len)); byteBuffer.clear(); } } it.remove(); } } } catch (IOException e) { e.printStackTrace(); } finally { if(ssChannel!=null){ try { ssChannel.close(); } catch (IOException e) { e.printStackTrace(); } } } }
注意:这里服务端用到的org.junit.Test;这个包方便测试,客户端因为需要读取输入所以写在Main函数中(@Test方法中测试出来好像不能读取输入)
需要下载包的地址如下:
链接:https://pan.baidu.com/s/14ZHHOnAD3ldNVcA3pmCoJQ
提取码:uqd9
谢谢浏览,如有问题直接评论,我会及时更改我的错误。
原文:https://www.cnblogs.com/huangzhenxiong/p/10372548.html