Java 網絡編程從阻塞式 Socket/ServerSocket,到多線程並發模型,再到連接池複用,最終演進為 NIO 非阻塞模型。本文系統梳理四種通訊模式的核心代碼骨架、適用場景與避坑指南。
// Client
Socket socket = new Socket(InetAddress.getLocalHost(), 5678);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = stdin.readLine()) != null) {
out.println(line);
if ("end".equals(line)) break;
System.out.println(in.readLine());
}
// Server(單線程,同一時間只能服務一個客戶端)
ServerSocket server = new ServerSocket(5678);
Socket client = server.accept();
// ... 同樣的讀寫循環 ...
public class SmartTcpServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(5678);
while (true) {
Socket client = server.accept();
new Thread(new ServerThread(client)).start();
}
}
}
class ServerThread implements Runnable {
private final Socket socket;
ServerThread(Socket socket) { this.socket = socket; }
public void run() {
// 處理該客戶端的完整讀寫邏輯
}
}
類比數據庫連接池,預創建 Socket[] 陣列 + 狀態陣列 boolean[],getConnection()/releaseConnection() 管理複用。適用於高頻短連接場景(如微服務 RPC 客戶端)。
DatagramSocket、DatagramPacket(封裝數據+目標地址/端口)。receive() 阻塞等待數據報。// Client
DatagramSocket socket = new DatagramSocket();
InetAddress host = InetAddress.getLocalHost();
byte[] buf = line.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, host, 5678);
socket.send(packet);
// Server
DatagramSocket ds = new DatagramSocket(5678);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
ds.receive(packet);
String msg = new String(buffer, 0, packet.getLength());
System.out.println(packet.getAddress().getHostName() + ": " + msg);
packet.setLength(buffer.length); // 重置長度供下次接收
}
MulticastSocket,關鍵方法 joinGroup(InetAddress)/leaveGroup()。// Sender
MulticastSocket ms = new MulticastSocket();
InetAddress group = InetAddress.getByName("230.0.0.1");
DatagramPacket packet = new DatagramPacket(buf, buf.length, group, 5678);
ms.send(packet);
// Receiver
MulticastSocket ms = new MulticastSocket(5678);
ms.joinGroup(InetAddress.getByName("230.0.0.1"));
// 接收循環同 UDP Server
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(5678));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel ch = (SocketChannel) key.channel();
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = ch.read(buf);
if (len > 0) {
buf.flip();
// 解碼處理...
}
}
}
selector.selectedKeys().clear();
}
| 模式 | 並發能力 | 延遲 | 實現複雜度 | 典型場景 |
|---|---|---|---|---|
| TCP 阻塞 + 多線程 | 中(受線程數限制) | 低 | 低 | 傳統業務服務、管理後台 |
| TCP 連接池 | 高(連接複用) | 低 | 中 | 高頻 RPC 客戶端、數據庫代理 |
| UDP | 極高(無連接狀態) | 極低 | 低 | 視頻會議、遊戲同步、日誌收集 |
| Multicast | 極高(一對多) | 極低 | 低 | 行情推送、集群發現 |
| NIO (Netty 等框架) | 極高(單線程萬連接) | 低 | 高(建議用 Netty) | IM、網關、高性能微服務 |
理解阻塞/非阻塞、連接/無連接、單播/多播的本質差異,結合業務對可靠性、延遲、併發的具體要求選型。現代高併發系統建議直接使用 Netty 等成熟 NIO 框架,避免重複造輪子;但在理解框架原理、排查網絡疑難雜症時,掌握原生 Socket/NIO 代碼模式不可或缺。