网络编程里,TCP 和 UDP 是绕不开的两个传输协议。TCP 保证可靠送达,三次握手之后建立连接,再通过流式传输收发数据;UDP 则是无连接的数据报方式,发出去就不管了,适合实时性要求高但对丢包不敏感的场景。
日常开发中接触更多的是 TCP,尤其是基于 Socket 的编程模型。Java 把底层的细节封装得还算干净,ServerSocket 和 Socket 两个类就能搭起最简单的客户端/服务端通信。写起来不复杂,但有几个点踩过坑之后印象会比较深:
server.accept()是阻塞的,没等到客户端连接就不会往下走。BufferedReader.readLine()读不到数据也会卡住,所以协议里最好约定好结束符或固定长度,不然两边都可能死等。- 带缓冲的输出流记得
flush(),否则数据可能一直留在本地缓冲区没发出去。
一个最简的回显(Echo)服务器大概是这样:
// 服务端
ServerSocket server = new ServerSocket(6666);
Socket socket = server.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String info = br.readLine();
PrintStream ps = new PrintStream(new BufferedOutputStream(socket.getOutputStream()));
ps.println("echo: " + info);
ps.flush();
ps.close();
br.close();
客户端连上后发一句话,再读回服务器拼接的 "echo: ..."。这种做法简单直接,适合用来理解通信流程,但真正工程里很少这样用:单连接、单线程,多个客户端同时过来就处理不了。
处理多个客户端:线程池 + 每连接一线程
要同时应付多个客户端,经典的做法是主线程只负责 accept,每拿到一个新的 Socket 就交给线程池去处理。这里用 Executors.newFixedThreadPool 限制并发线程数,避免资源耗尽。
ServerSocket server = ();
Executors.newFixedThreadPool();
() {
server.accept();
System.out.println( + socket.getInetAddress().getHostAddress());
es.execute( (socket));
}

