使用NIO实现非阻塞式的网络通信
来源:互联网 发布:中老年服饰淘宝模特 编辑:程序博客网 时间:2024/05/17 23:56
实现这样一个程序:客户端读取键盘输入,并发送到服务器端,服务器端接收信息并打印。
首先先写一个阻塞式的程序:
package nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;import java.util.Date;import java.util.Scanner;import org.junit.Test;public class TestBlocking { @Test public void client() throws IOException { // 获取通道 SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888)); // 分配1024字节大小的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); Scanner scan = new Scanner(System.in); // 输入 while (scan.hasNext()) { String str = scan.next(); buffer.put((new Date().toString() + "\n" + str).getBytes()); // 切换回读模式,实质是令limit=position;position=0。 buffer.flip(); // 写入通道 socketChannel.write(buffer); // 清空缓冲区 buffer.clear(); } } @Test public void server() throws IOException { // 获取服务器端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 绑定端口号 serverSocketChannel.bind(new InetSocketAddress(8888)); // 接收客户端通道 SocketChannel socketChannel = serverSocketChannel.accept(); // 分配缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); // 每次读取数据的长度 int len; // 接收数据 while ((len = socketChannel.read(buffer)) > 0) { buffer.flip(); // 将每次读取的数据输出 System.out.println(new String(buffer.array(), 0, len)); buffer.clear(); } }}
运行程序(注意先启动server,再启动client),发现当只有一个server一个client时可以正常运行:
但是再运行一遍client以添加一个client线程,会发现第二次添加的client线程发送的信息无法显示,这是因为,服务器端的线程一直阻塞在接收第一个客户端线程发送信息的位置,即63行,无法接收第二个客户端线程的连接请求。
现在,我们使用NIO来实现非阻塞式的程序,以解决上述问题:
package nio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.file.Paths;import java.nio.file.StandardOpenOption;import java.util.Date;import java.util.Iterator;import java.util.Scanner;import org.junit.Test;public class TestNonBlocking { @Test public void client() throws IOException { // 获取通道 SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888)); // 分配1024字节大小的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); Scanner scan = new Scanner(System.in); // 输入 while (scan.hasNext()) { String str = scan.next(); buffer.put((new Date().toString() + "--" + str).getBytes()); // 切换回读模式,实质是令limit=position;position=0。 buffer.flip(); // 写入通道 socketChannel.write(buffer); // 清空缓冲区 buffer.clear(); } } @Test public void server() throws IOException { // 获取服务器端通道 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // 切换该通道为非阻塞模式 serverSocketChannel.configureBlocking(false); // 绑定端口号 serverSocketChannel.bind(new InetSocketAddress(8888)); // 获取选择器 Selector selector = Selector.open(); // 将通道注册到选择器上,并指定监听的事件类型为“接收” serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 轮询式地获取选择器上已经准备就绪的事件 //selector.select()方法是阻塞的 while (selector.select() > 0) { // 获取当前选择器中所有已经注册的“选择键”,即已就绪的监听事件 Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { // 获取已经准备就绪的事件 SelectionKey selectionKey = it.next(); // 判断事件的类型 // 接收类型 if (selectionKey.isAcceptable()) { // 接收客户端通道 SocketChannel socketChannel = serverSocketChannel.accept(); socketChannel.configureBlocking(false); socketChannel.register(selector, selectionKey.OP_READ); } else if (selectionKey.isReadable()) { // 获取当前选择器上“读就绪”状态的通道 SocketChannel socketChannel = (SocketChannel) selectionKey.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); int len; while ((len = socketChannel.read(buffer)) > 0) { buffer.flip(); System.out.println(new String(buffer.array(), 0, len)); buffer.clear(); } } // 取消选择键 SelectionKey it.remove(); } } }}
再次运行程序,发现即使在多个client线程的情况下,程序也能正常运行:
0 0
- 使用NIO实现非阻塞式的网络通信
- 使用NIO实现非阻塞Socket通信
- 使用NIO实现非阻塞Socket通信
- NIO实现TCP的非阻塞通信
- Java网络编程——使用NIO实现非阻塞Socket通信
- Java网络编程——使用NIO实现非阻塞Socket通信
- Java网络编程之(三): TCP协议使用NIO实现非阻塞Soket通信
- Java网络编程——使用NIO实现非阻塞Socket通信
- Java网络编程之(三): TCP协议使用NIO实现非阻塞Soket通信
- NIO的非阻塞通信
- Thinking in Java--使用NIO实现非阻塞Socket通信
- 使用NIO实现非阻塞Socket通信原理
- Java 之NIO(五) - 非阻塞式网络通信
- NIO基础(3)-非阻塞式网络通信
- 使用 JSSE 和 NIO 实现非阻塞通信的一种快速方法
- java中使用nio包实现非阻塞的UDP通信
- java NIO 实现非阻塞socket通信
- NIO Socket实现非阻塞通信示例
- Linux之grub的运行机制及grub修复
- 1.Android入门
- 蓝桥杯 算法训练01 Java实现
- Laravel 自动加载
- Postgresql 条件表达式
- 使用NIO实现非阻塞式的网络通信
- 基于最大稳定区域的图像分割算法
- 利用Java反射实现JavaBean对象相同属性复制并初始化目标对象为空的属性的BeanUtils
- HTML/CSS基础
- Vue项目搭建
- linux error: expected declaration specifiers or '...' XXX
- Ant Counting POJ - 3046 多重集组合数
- Web项目程序怎么发布部署
- 求FFFF:0到FFFF:F的字节型数据和,存放到dx中(LOOP和ds:[bx]联合运用)