利用NIO的ServerSocketChannel实现的客户端与服务端通信
基础知识
一、使用 NIO 完成网络通信的三个核心:
1. 通道(Channel):负责连接
java.nio.channels.Channel 接口:
|--SelectableChannel
|--SocketChannel
|--ServerSocketChannel
|--DatagramChannel
|--Pipe.SinkChannel
|--Pipe.SourceChannel
2. 缓冲区(Buffer):负责数据的存取
3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况
二、服务端开发流程
- 获取通道
- 切换非阻塞模式
- 绑定连接
- 获取选择器
- 将通道注册到选择器上, 并且指定“监听接收事件”
- 轮询式的获取选择器上已经“准备就绪”的事件
- 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
- 获取准备“就绪”的是事件
- 判断具体是什么事件准备就绪
- 若“接收就绪”,获取客户端连接
- 客户端链接切换非阻塞模式
- 将该通道注册到选择器上
- 获取当前选择器上“读就绪”状态的通道
- 读取数据
三、客户开发流程
- 获取通道
- 切换非阻塞模式
- 分配指定大小的缓冲区
- 发送数据给服务端
四、代码实例
package cn.com.github.nio.file;
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.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
/**
* 类的描述信息
*
* @author panzhuowen
* @version 1.0.1
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(8089));
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {
SelectionKey selectionKey = iterator.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 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();
}
}
}
iterator.remove();
}
}
}
package cn.com.github.nio.file;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Scanner;
/**
* 类的描述信息
*
* @author panzhuowen
* @version 1.0.1
*/
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8089));
ByteBuffer buf = ByteBuffer.allocate(1024);
//4. 发送数据给服务端
Scanner scan = new Scanner(System.in);
while(scan.hasNext()){
String str = scan.next();
buf.put((new Date().toString() + "\n" + str).getBytes());
buf.flip();
socketChannel.write(buf);
buf.clear();
}
//5. 关闭通道
socketChannel.close();
}
}