1、阻塞模式
我们通过代码来理解阻塞模式。
首先我们先创建服务器,代码如下:
public class Server {
public static void main(String[] args) throws Exception {
// 单线程模式
List<SocketChannel> socketChannelList = new ArrayList<>();
// 创建服务器
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8000));
System.out.println("创建服务器。");
while (true) {
// 建立socket连接
System.out.println("准备和客户端进行连接...");
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannelList.add(socketChannel);
System.out.println("接收到客户端的连接:" + socketChannel);
// 处理客户端发送的数据
ByteBuffer buffer = ByteBuffer.allocate(24);
for (SocketChannel item : socketChannelList) {
System.out.println("准备处理客户端的数据...");
item.read(buffer);
// 读bytebuffer,看下里面的内容
buffer.flip();
System.out.println("接受到客户端消息:" + Charset.defaultCharset().decode(buffer));
buffer.compact();
}
}
}
}
这时,我们将服务器运行后,查看代码输出情况:

通过输出,我们可以看到当代码到达accept()方法时,程序无法继续往下执行。此时我们建立一个客户端程序:
public class Client {
public static void main(String[] args) throws Exception {
// 连接客户端
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("localhost", 8000));
System.out.println();
}
}
运行客户端程序后,我们查看服务端的输出情况:

由此可以看出,accept()方法是一个阻塞方法,服务器端只有收到了客户端的连接请求后,才会继续往下执行。
同时,服务器端在到达read()方法时,程序同样无法继续往下执行。此时,通过调试模式,在客户端发送消息给服务器:

此时查看服务器端的输出情况:

由此可以看出,read()方法同样是一个阻塞方法,服务器端只有收到了客户端发送的消息后,才会继续往下执行。
并且,由于此时服务端的代码阻塞在客户端连接处,那么即使客户端继续发送消息,服务端也不会进行处理,直到等到下一个新的连接请求出现后,才会统一进行处理。
2、非阻塞模式
想要将上述阻塞模式代码改为非阻塞模式,那么仅需设置configureBlocking为false即可。
public class Server {
public static void main(String[] args) throws Exception {
List<SocketChannel> socketChannelList = new ArrayList<>();
// 创建服务器
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(8000));
serverSocketChannel.configureBlocking(false);
System.out.println("创建服务器。");
while (true) {
// 建立socket连接
System.out.println("准备和客户端进行连接...");
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel != null) {
// 设置成非阻塞模式
socketChannel.configureBlocking(false);
socketChannelList.add(socketChannel);
}
System.out.println("接收到客户端的连接:" + socketChannel);
// 处理客户端发送的数据
ByteBuffer buffer = ByteBuffer.allocate(24);
for (SocketChannel item : socketChannelList) {
System.out.println("准备处理客户端的数据...");
int result = item.read(buffer);
if(result != 0) {
// 读bytebuffer,看下里面的内容
buffer.flip();
System.out.println("接受到客户端消息:" + Charset.defaultCharset().decode(buffer));
buffer.compact();
}
}
}
}
}
在阻塞模式下,accept()方法和read()方法都会进行阻塞,只有等到新的连接或者消息才会继续往下执行。而在非阻塞模式下,线程不会停止,accespt()方法如果有新的连接,那么就位连接channel,否则为null;而读消息时,如果没有新的消息,那么read()方法将返回0。
非阻塞模式,会导致CPU的浪费。
Comments NOTHING