Java 网络编程:TCP 与 UDP 的「通信江湖」(基于TCP回显服务器)
Java 网络编程:TCP 与 UDP 的「通信江湖」(基于TCP回显服务器)
上篇博客写了关于UDP的基础特性和基于UDP回显服务器,书接上回,今天,我们就来好好聊聊 TCP,从基础特性到工作机制最后构建回显服务器,揭开它 “靠谱” 的秘密。
UDP与TCP的最主要的核心区别就是UDP为无连接,不可靠传输,面向数据报,UDP为有连接,可靠传输,面向字节流。二者都为全双工,此篇不再重点介绍。
一、TCP 协议:面向连接的可靠传输
UDP的核心特征为:有连接,可靠传输,面向字节流和全双工
1.核心技术特征
- 有连接: 对于 TCP 来说,TCP 协议中,就已经保存了对端的信息
- 可靠传输: 确保数据无丢失、无重复、按序交付,尽可能的提高传输成功的概率
- 面向字节流:数据以连续字节为单位传输
- 全双工: 一个通信链路,支持双向通信,能读也能写
2. Java 中 TCP 的实现
API 介绍
ServerSocket:
ServerSocket 是创建TCP服务端Socket的API。
构造⽅法:
| ⽅法签名 | ⽅法说明 | 
|---|---|
| ServerSocket(int port) | 创建⼀个服务端流套接字Socket,并绑定到指定端⼝ | 
⽅法:
| ⽅法签名 | ⽅法说明 | 
|---|---|
| Socket accept() | 开始监听指定端⼝(创建时绑定的端⼝),有客⼾端连接后,返回⼀个服务端Socket对象,并基于该Socket建⽴与客⼾端的连接,否则 阻塞等待 | 
| void close() | 关闭此套接字 | 
TCP是“有连接”,这里的accept是联通连接的关键
Socket:
Socket 是客⼾端Socket,或服务端中接收到客⼾端建⽴连接(accept⽅法)的请求后,返回的服
务端Socket。
不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后,保存的对端信息,及⽤来与对⽅收发数据
的。
构造⽅法:
| ⽅法签名 | ⽅法说明 | 
|---|---|
| Socket(String host, int port) | 创建⼀个客⼾端流套接字Socket,并与对应IP的主机上,对应端⼝的进程建⽴连接 | 
这两个参数是服务器IP和端口号
⽅法:
| ⽅法签名 | ⽅法说明 | 
|---|---|
| InetAddress getInetAddress() | 返回套接字所连接的地址 | 
| InputStream getInputStream() | 返回此套接字的输⼊流( 字节流对象) | 
| OutputStream getOutputStream() | 返回此套接字的输出流( 字节流对象) | 
二、构造TCP Echo Server
服务器主要思路:
- 读取请求并解析
- 根据请求计算响应
- 返回响应到客户端
- 打印日志
代码⽰例:
public class TcpEchoServer {private ServerSocket serverSocket=null;//这里和udp服务器类似,也是在构造对象的时候,绑定端口号public TcpEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");try {while (true) {//tcp 来说,需要先处理客户端发来的连接//通过读写clientsocket,和客户端进行连接//如果没有客户端发起连接,此时accept就会阻塞Socket clientSocket = serverSocket.accept();processConnection(clientSocket);}}finally{serverSocket.close();}          }}//处理一个客户端的连接//可能要涉及到多个客户端的请求和响应private void processConnection(Socket clientSocket) {//打印日志System.out.printf("[%s:%d]客户端上线!\n",clientSocket.getInetAddress(),clientSocket.getPort());try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()){//针对 InputStream 套了一层Scanner scanner=new Scanner(inputStream);//针对 OutputStram 套了一层PrintWriter writer=new PrintWriter(outputStream);//分成三个步骤while (true){//1.读取请求并解析,可以直接read,也可以借助Scanner 来辅助if (!scanner.hasNext()){System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress(),clientSocket.getPort());//连接断开了break;}String request=scanner.next();//2.根据请求计算响应String response=process(request);//3.返回响应到客户端//outputStream.write(response.getBytes());writer.println(response);//打印日志System.out.printf("[%s:%d] rep: %s, resp: %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);}} catch (IOException e) {e.printStackTrace();}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server=new TcpEchoServer(9090);server.start();}
}重点细节解析:
客户端主要思路:
- 从控制台读取用户输入
- 发送给服务器
- 读取服务器返回的响应
- 打印到控制台
代码⽰例:
public class TcpEchoClient {private Socket socket=null;public  TcpEchoClient(String sergerIp,int serverPort) throws IOException {//直接把字符串的IP,设置进来//127.0.0.0这种字符串socket=new Socket(sergerIp,serverPort);}public  void start(){Scanner scanner=new Scanner(System.in);try(InputStream inputStream=socket.getInputStream();OutputStream outputStream=socket.getOutputStream()){//为了使用方便,套壳使用Scanner scannerNet=new Scanner(inputStream);PrintWriter writer=new PrintWriter(outputStream);//从控制读取请求,发送给服务器while (true){//1.从控制台读取用户输入String requset=scanner.next();//2.发送给服务器writer.println(requset);//3.读取服务器返回的响应String response=scannerNet.next();//打印到控制台System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient client=new TcpEchoClient("127.0.0.1",9090);client.start();}
}重点细节解析:
三、小结:Java 网络编程的 “入门钥匙”
TCP 和 UDP 是 Java 网络编程的基础,记住这两点:
- 要 “靠谱” 选 TCP:需要确认、有序的场景(比如用户登录时传密码,不能丢);
- 要 “极速” 选 UDP:能接受偶尔丢包、追求速度的场景(比如游戏里的角色移动,丢一两个帧不影响)。
其实你再深入想一层:平时用的 HTTP 协议(上网刷网页)是基于 TCP 的,而直播用的 RTMP 协议很多是基于 UDP 的 —— 原来这两个 “通信高手” 早就藏在我们每天的操作里啦!
如果想进一步玩起来,可以试试修改上面的代码:比如让 TCP 客户端和服务端互相聊天(加个循环读取输入),或者让 UDP 接收方给发送方回消息(类似 “已读” 确认),动手的过程中理解会更透彻~







