package com.nio.client; import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; 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.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Iterator; import java.util.Set; public class NIOServer { /* 缓冲区大小 */ private static final int BLOCK_SIZE = 4096; /* 接收数据缓冲区大小 */ private ByteBuffer recieveBuffer = ByteBuffer.allocate(BLOCK_SIZE); /* 发送数据缓冲区大小 */ private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE); /*持有一个Selector*/ private Selector selector; public NIOServer(){ } public NIOServer(int port) throws IOException{ /*SocketServerChannel:可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样*/ /*创建服务器套接字通道:SocketServerChannel,内部就是实例化了一个SocketServerChannelImpl*/ ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); /* 服务器配置为非阻塞 */ serverSocketChannel.configureBlocking(Boolean.FALSE); /* 获取一个socket */ ServerSocket serverSocket = serverSocketChannel.socket(); /* 通过socket 绑定地址 */ serverSocket.bind(new InetSocketAddress("localhost",port)); /* 获取Selector:实际上window是创建了WindowsSelectorImpl实例 */ selector = Selector.open(); /* 注册到accept事件到 selector,等待连接 */ serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("NIO Server Start........................."); } /**一直不断的监听*/ public void listen() throws IOException { while (true){ // 监控注册在Selector上的ServerSocketChannel,返回值代表有多少channel已经就绪,可以进行I/O操作了 int ready = selector.select(); if (ready > 0) { /* * selectedKeys()返回一个SelectionKey的集合,因为完全有可能在这个Selector注册多个SelectionKey * 比如OP_ACCEPT,OP_READ,OP_WRITE等 * 其中每个SelectionKey代表了一个可以进行IO操作的channel * 一个ServerSocketChannel可以进行IO操作意味着有新的TCP连接连入了 */ Set<SelectionKey> keys = selector.selectedKeys(); SelectionKey key = null; for(Iterator<SelectionKey> it = keys.iterator();it.hasNext();){ key = (SelectionKey)it.next(); // 需要将处理过的key从selectedKeys这个集合中删除 it.remove(); handleKey(key); } } } } /**处理请求*/ public void handleKey(SelectionKey key) throws IOException{ if (key == null) { System.out.println("SelectionKey is null"); return; } ServerSocketChannel serverSocketChannel = null; SocketChannel socketChannel = null; Socket socket = null; int count = 0; /* 判断这个SelectionKey对应的channel是否已准备好接收新的TCP连接 */ if (key.isAcceptable()) { /* 从SelectionKey得到对应的channel */ serverSocketChannel = (ServerSocketChannel)key.channel(); /* 接受新的TCP连接(来自客户端) */ socketChannel = serverSocketChannel.accept(); /* 配置为非阻塞 */ socketChannel.configureBlocking(Boolean.FALSE); /* 注册到selector,等待读取 */ socketChannel.register(selector,SelectionKey.OP_READ); } else if (key.isReadable()) { //判断该通道是否已准备好读 /* 返回为之创建此键的通道 */ socketChannel = (SocketChannel)key.channel(); /* 将接收数据的缓冲区清空以备下次读取 */ recieveBuffer.clear(); /* 读取服务器发送的数据到recieveBuffer */ count = socketChannel.read(recieveBuffer); if (count >0) { String recvText = new String(recieveBuffer.array(),0,count); System.out.println("服务器端接受客户端数据--: " + recvText); socketChannel.register(selector, SelectionKey.OP_WRITE); } } else if (key.isWritable()) {//判断该通道是否已准备好写 socketChannel = (SocketChannel)key.channel(); /* 将缓冲区清空以备下次写入 */ sendBuffer.clear(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String data = dateFormat.format(new Date()); /* 向缓冲区中输入数据 */ sendBuffer.put(data.getBytes(Charset.defaultCharset())); /* 将数据输出到通道*/ socketChannel.write(sendBuffer); System.out.println("服务器端向客户端发送数据--: " + data); /* 又注册到selector,等待读取 */ socketChannel.register(selector, SelectionKey.OP_READ); } } public static void main(String[] args) throws IOException { int port = 22222; NIOServer server = new NIOServer(port); server.listen(); }}
package com.nio.client; import java.io.IOException; 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.nio.charset.Charset; import java.util.Iterator; import java.util.Set; public class NIOClient { /* 缓冲区大小 */ private static final int BLOCK_SIZE = 4096; /* 接收数据缓冲区大小 */ private ByteBuffer recieveBuffer = ByteBuffer.allocate(BLOCK_SIZE); /* 发送数据缓冲区大小 */ private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK_SIZE); /* 服务器端地址 */ private final static InetSocketAddress SERVER_ADDRESS = new InetSocketAddress("localhost", 22222); public void handle() throws IOException{ /* 创建一个SocketChannel */ SocketChannel socketChannel = SocketChannel.open(); /* 设为非阻塞模式 */ socketChannel.configureBlocking(Boolean.FALSE); /* 创建Selector */ Selector selector = Selector.open(); /* 注册连接服务端socket动作 */ socketChannel.register(selector, SelectionKey.OP_CONNECT); /* 连接到服务器 */ socketChannel.connect(SERVER_ADDRESS); Set<SelectionKey> keys = null; Iterator<SelectionKey> it = null; SelectionKey key = null; int count = 0; String recvText = null; while (true) { /* 监控注册在Selector上的SocketChannel,返回值代表有多少channel已经就绪,可以进行I/O操作了*/ int ready = selector.select(); /* 其中每个SelectionKey代表了一个可以进行IO操作的channel */ keys = selector.selectedKeys(); it = keys.iterator(); while (it.hasNext()) { key = (SelectionKey)it.next(); // 判断该通道是否可以进行连接操作 if (key.isConnectable()) { System.out.println("客户端开始连接......"); /* 返回为之创建此键的通道 */ socketChannel = (SocketChannel)key.channel(); if (socketChannel.isConnectionPending()) { socketChannel.finishConnect(); System.out.println("完成连接!"); sendBuffer.clear(); sendBuffer.put("我可以连接吗".getBytes(Charset.defaultCharset())); sendBuffer.flip(); socketChannel.write(sendBuffer); } /* 又注册到selector,等待读取 */ socketChannel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { //判断该通道是否可以读 /* 返回为之创建此键的通道 */ socketChannel = (SocketChannel)key.channel(); //将接收数据缓冲区清空以备下次读取 recieveBuffer.clear(); //读取服务器发送来的数据到缓冲区中 count = socketChannel.read(recieveBuffer); if (count > 0) { recvText = new String(recieveBuffer.array(),0,count,Charset.defaultCharset()); System.out.println("客户端接受服务器端数据=> "+recvText); /* 又注册到selector,等待写入 */ socketChannel.register(selector, SelectionKey.OP_WRITE); } } else if (key.isWritable()) { //判断该通道是否可以写 /* 返回为之创建此键的通道 */ socketChannel = (SocketChannel)key.channel(); //将发送数据缓冲区清空以备下次读取 sendBuffer.clear(); String data = String.valueOf(Math.round(Math.random() * 100 + 1)); sendBuffer.put(data.getBytes(Charset.defaultCharset())); //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位 sendBuffer.flip(); socketChannel.write(sendBuffer); System.out.println("客户端向服务器端发送数据=> " + data); socketChannel.register(selector, SelectionKey.OP_READ); } } keys.clear(); } } public static void main(String[] args) throws IOException { NIOClient client = new NIOClient(); client.handle(); } }
nio demo
最新推荐文章于 2022-11-09 19:14:33 发布