服务端: 接受请求 ----> ServerSocketChannel
进行通信--------------->SocketChannel
public class MyServer {
public static void main(String[] args) throws IOException {
//1. 创建ServerScoketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2. 设置服务端的监听端口:---》client通过网络进行访问 ip:port http://localhost:8989
serverSocketChannel.bind(new InetSocketAddress(8000));
List<SocketChannel> channelList = new ArrayList<>();
ByteBuffer buffer = ByteBuffer.allocate(20);
//3. 接受client的连接
while (true) {
//4. ScoketChannle 代表 服务端与Client链接的一个通道
System.out.println("等待连接服务器...");
SocketChannel socketChannel = serverSocketChannel.accept();//阻塞 程序等待client
System.out.println("服务器已经连接..."+socketChannel);
channelList.add(socketChannel);
//5. client与服务端 通信过程 NIO代码
for (SocketChannel channel : channelList) {
System.out.println("开始实际的数据通信....");
channel.read(buffer);//阻塞 对应的IO通信的阻塞
buffer.flip();
CharBuffer decode = Charset.forName("UTF-8").decode(buffer);
System.out.println("decode.toString() = " + decode.toString());
buffer.clear();
System.out.println("通信已经结束....");
}
}
}
}
通过这版代码 证明了 服务器端 存在2中阻塞
- 连接阻塞 ----> accept方法存在阻塞---> ServerSocketChannel阻塞。
- IO阻塞 ----> channel的read方法存在阻塞---> SocketChannel阻塞。
Seletor循环监听事件的方式 解决死循环空转的问题。
public class MyServer2 {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8000));
serverSocketChannel.configureBlocking(false);//Selector 只有在非阻塞的情况下 才可以使用。
//引入监管者
Selector selector = Selector.open();//1. 工厂,2. 单例
//监管者 管理谁? selector.xxxx(ssc); //管理者 ssc ---> Accept
SelectionKey selectionKey = serverSocketChannel.register(selector, 0, null);
// selector监控 SSC ACCEPT
// selector
// keys --> HashSet
// register注册 ssc
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
System.out.println("MyServler2.main");
//监控
while (true) {
selector.select();//等待.只有监控到了 有实际的连接 或者 读写操作 ,才会处理。
//对应的 有ACCEPT状态的SSC 和 READ WRITE状态的 SC 存起来
// SelectionsKeys HashSet
System.out.println("-------------------------");
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()) {//ServerSocketChannel ScoketChannel
SelectionKey key = iterator.next();
//用完之后 就要把他从SelectedKeys集合中删除掉。问题? ServerScoketChannel---SelectedKeys删除 ,后续 SSC建立新的连接?
iterator.remove();
if (key.isAcceptable()) {
//serverSocketChannel.accept();
ServerSocketChannel channel = (ServerSocketChannel) key.channel();
SocketChannel sc = channel.accept();
sc.configureBlocking(false);
//监控sc状态 ---> keys
SelectionKey sckey = sc.register(selector, 0, null);
sckey.interestOps(SelectionKey.OP_READ);
} else if (key.isReadable()) {
try {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(5);
int read = sc.read(buffer);
if (read == -1) {
key.cancel();
} else {
buffer.flip();
System.out.println("Charset.defaultCharset().decode(buffer).toString() = " + Charset.defaultCharset().decode(buffer).toString());
}
} catch (IOException e) {
e.printStackTrace();
key.cancel();
}
}
}
}
}
}