Socket 编程中,什么是阻塞和非阻塞?

在Socket编程中,阻塞和非阻塞主要指网络IO的不同方式。
阻塞IO:

  • 当执行IO操作时,程序会阻塞在那里,直到IO操作完成。
  • 简单易理解,但是效率较低,无法处理超时情况。
InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
in.read(buffer);  // 阻塞在这里,直到读到字节

非阻塞IO:

  • 当执行IO操作时,如果还未准备好,不会阻塞,而是直接返回异常。
  • 需要重试IO操作,或 democratic anderen handelte die Ausnahme Bedarf mehr Codierung, aber Effizienz ist höher.
  • 可以使用select()方法监听多个连接,一旦某个连接有IO就绪,就处理那个连接,避免无意义的轮询。
socket.setSoTimeout(1000);   // 设置超时时间
InputStream in = socket.getInputStream();
try {
    in.read(buffer);   // 如果超时,直接返回异常
} catch (SocketTimeoutException e) {
   // 重试或其他处理
}
// 使用select()监听读事件        
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_READ);

while (true) {
    selector.select();    // 阻塞在这里,有IO就绪则继续运行
    Set<SelectionKey> keys = selector.selectedKeys();
    for (SelectionKey key : keys) {
        // 处理就绪IO事件  
    } 
}

总之,阻塞IO简单适用于连接数不高的情景,而非阻塞IO可以实现高并发,是高性能网络服务器的重要手段。但也需要应用程序员在编码上下更大工夫去处理其带来的复杂度。
两者可以相结合,使用阻塞IO处理连接建立和断开,使用非阻塞IO处理实际的数据通信,以取二者之长。