NIO实现TCP网络通信
传统socket采用的是阻塞IO模式来实现的Socket通信,这里的阻塞实际上就是程序和内核交互时的模式,在NIO中可以利用NIO的特性实现非阻塞形式的Socket通信
1. 实现步骤
- 实现服务端的端口监听
- 实现服务端获取客户端连接并注册到Selector中
- 实现消息解析
- 实现客户端代码并测试
2. 服务端实现
2.1 实现服务端的端口监听
public class MyServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
/**
* 开启服务端
*/
public void start(Integer port) throws Exception{
serverSocketChannel = ServerSocketChannel.open();
selector = Selector.open();
//绑定监听端口
serverSocketChannel.socket().bind(new InetSocketAddress(port));
//设置为非阻塞模式
serverSocketChannel.configureBlocking(false);
//注册到Selector上
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
startListener();
}
/**
* 真正的监听是否有客户端请求
*/
private void startListener() throws Exception {
while (true) {
// 如果客户端有请求select的方法返回值将不为零
if (selector.select(1000) == 0) {
System.out.println("current not exists task");
continue;
}
// 如果有事件集合中就存在对应通道的key
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
}
}
}
2.2 实现连接处理
- 只需要遍历刚刚获得的所有有事件的key并找出其中事件类型为Accept的key,将对应的通道在注册到selector上即可
private void startListener() throws Exception {
while (true) {
if (selector.select(1000) == 0) {
System.out.println("current not exists task");
continue;
}
// 如果有事件集合中就存在对应通道的key
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
// 遍历所有的key找到其中事件类型为Accept的key
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable())
handleConnection();
iterator.remove();
}
}
}
/**
* 处理建立连接
*/
private void handleConnection() throws Exception {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
}
2.4 消息处理
- 只需要遍历刚刚获得的所有有事件的key并找出其中事件类型为Readable的key,获取通道中的消息
private void startListener() throws Exception {
while (true) {
if (selector.select(1000) == 0) {
System.out.println("current not exists task");
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable())
handleConnection();
if (key.isReadable())
handleMsg(key);
iterator.remove();
}
}
}
private void handleMsg(SelectionKey key) throws Exception {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer attachment = (ByteBuffer) key.attachment();
channel.read(attachment);
System.out.println("current msg: " + new String(attachment.array()));
}
2.5 服务端完整代码
public class MyServer {
private ServerSocketChannel serverSocketChannel;
private Selector selector;
public void start(Integer port) throws Exception{
serverSocketChannel = ServerSocketChannel.open();
selector = Selector.open();
serverSocketChannel.socket().bind(new InetSocketAddress(port));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
startListener();
}
private void startListener() throws Exception {
while (true) {
if (selector.select(1000) == 0) {
System.out.println("current not exists task");
continue;
}
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
if (key.isAcceptable())
handleConnection();
if (key.isReadable())
handleMsg(key);
iterator.remove();
}
}
}
private void handleMsg(SelectionKey key) throws Exception {
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer attachment = (ByteBuffer) key.attachment();
channel.read(attachment);
System.out.println("current msg: " + new String(attachment.array()));
}
private void handleConnection() throws Exception {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
}
public static void main(String[] args) throws Exception {
MyServer myServer = new MyServer();
myServer.start(8888);
}
}
3. 客户端实现
public class MyClient {
public static void main(String[] args) throws Exception {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
// 链接服务器
if (!socketChannel.connect(new InetSocketAddress("127.0.0.1", 8888))) {
while (!socketChannel.finishConnect()) {
System.out.println("connecting...");
}
}
//发送数据
String str = "hello netty";
ByteBuffer byteBuffer = ByteBuffer.wrap(str.getBytes());
socketChannel.write(byteBuffer);
System.in.read();
}
}