public class NioServer {
public static void main(String[] args) {
ServerSocketChannel serverSocketChannel;
Selector selector;
try {
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(2222));
serverSocketChannel.configureBlocking(false);
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (true) {
try {
selector.select(); // 设置为非阻塞,无输数据则selectedKeys为空
} catch (IOException e) {
e.printStackTrace();
break;
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
try {
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
ByteBuffer buffer = ByteBuffer.allocate(74);
buffer.put(new Date().toString().getBytes());
buffer.put((byte) '\r');
buffer.put((byte) '\n');
buffer.flip();
key2.attach(buffer);
} else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = (ByteBuffer) key.attachment();
//if (!buffer.hasRemaining()) { // 判断是否还有空间 position到limit
buffer.rewind();
buffer.put(new Date().toString().getBytes());
buffer.put((byte) '\r');
buffer.put((byte) '\n');
buffer.flip();
// }
client.write(buffer);
}
} catch (IOException e) {
key.cancel();
try {
key.channel().close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
}
备注:
- clear()清空缓冲区,位置设为0,限制设置为容量大小
侧重于还原一切状态,通常为一系列新的通道读取或写入操作做好准备 - flip() limit设置为当前position,position设置为0
侧重于substring()截取 - rewind()position设置为0
侧重于重新,重新读取、重新写入。
public class NioClient {
public static void main(String[] args) {
SocketAddress address = new InetSocketAddress("localhost", 2222);
try {
SocketChannel client = SocketChannel.open(address);
client.configureBlocking(false); // true阻塞,false不阻塞
ByteBuffer buffer = ByteBuffer.allocate(74); // 申请字节大小
WritableByteChannel out = Channels.newChannel(System.out);
while (true) {
int n = client.read(buffer);// 在非阻塞模式下,read()可能因为读不到任何数据而返回0,阻塞模式下就会一直阻塞到有数据
if (n > 0) {
buffer.flip(); // 翻转
out.write(buffer);
buffer.clear(); // 清空缓存区
} else if (n == -1) {
// 不会发生
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
依次启动服务端,客户端,客户端收到当前时间消息。
确认同步,阻塞的概念:网上说的乱七八糟:
同步不同步取决于一次可以处理几个请求,阻塞不阻塞取决于服务端处理客户端请求,客户端处理服务端返回数据是否有阻塞可能
- bio:同步阻塞,一次只能处理一个请求
传统SocketServer.accept()阻塞直到有新的客户端接入,在当前对客户
端的处理工作未同步完成前,不能完全其它工作。Socket.getInputStream()阻塞直到有数据流。
- nio:同步阻塞/同步非阻塞,可以配置非阻塞模式,一次只能处理一个请求
可以通过设置configureBlocking来决定是否为阻塞模式,非阻塞情况下,客户端SocketChannel.read()读不到数据则返回0。服务端selector.select()无数据,则selectedKey为空Set,ServerSocketChannel.accept()无客户端连接,立即返回null。
- aio:异步非阻塞,一次可以处理多个请求
参考书籍《Java网络编程(第四版)》《Nio与Socket编程技术指南》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。