写网络编程时,你是不是也纠结过:同样是 Socket 编程,TCP 和 UDP 到底该怎么选?为啥传文件要用 TCP,玩游戏却用 UDP?实则答案藏在它们的 “性格” 里 —— 一个追求 “稳”,一个追求 “快”。今天用大白话拆解两者在编程中的核心区别,再用代码演示 “怎么用 TCP 聊天、用 UDP 传消息”,看完你再也不会选错!
一、先搞懂:Socket 里的 TCP 和 UDP,就像 “打电话” 和 “发传单”
Socket 是网络编程的 “工具”,而 TCP 和 UDP 是两种 “使用工具的方式”,用生活场景一对比就清楚:
TCP 编程就像 “打电话”:
必须先拨号(建立连接),等对方接了才能说话(传数据),说话时对方会 “嗯、嗯” 回应(确认收到),挂电话还要说 “再见”(断开连接)。优点是 “稳”—— 说的话对方肯定能听清,还不会乱序;缺点是 “麻烦”—— 步骤多,耗时间。
UDP 编程就像 “发传单”:
不用管对方在不在,拿起传单(数据)直接往对方地址扔(发送),扔完就走,不管对方收没收到。优点是 “快”—— 不用等,效率高;缺点是 “糙”—— 传单可能被风吹丢(数据丢失),也可能后发的先到(乱序)。
举个直观的例子:
用 TCP 做即时聊天:你说 “吃饭了吗”,对方肯定能收到,还能按顺序回复 “吃了”,不会出现 “吃了” 比 “吃饭了吗” 先到的情况;
用 UDP 做游戏走位:你按 “上” 键移动,服务器就算漏收一两个指令,后续的 “上”“右” 指令也能让角色继续动,总比等确认导致卡顿强。
二、4 大核心区别:编程时怎么选,看这张表就够了
许多人写 Socket 程序时选错协议,实则对比 “连接、数据、效率、代码” 这四点,立马就能确定用哪个:
对比维度 TCP Socket 编程 UDP Socket 编程
连接方式 必须先connect()建立连接,像打电话拨号 不用连接,直接sendto()发数据,像扔传单
数据传输 用InputStream/OutputStream流传输,保证顺序和完整 用DatagramPacket包传输,可能丢包、乱序
效率速度 较慢(要确认、重传) 较快(不用等确认)
代码复杂度 高(要处理连接、流关闭) 低(直接发、直接收)
适用场景 文件传输、聊天、登录(需可靠) 游戏、直播、广播(需快速)
三、实战案例:用代码演示 “TCP 聊天” 和 “UDP 传消息”
光说不练假把式,我们分别用 TCP 和 UDP 实现简单的 “客户端给服务器发消息”,看看代码和效果有啥不同。
1. TCP Socket 编程:像打电话一样聊天(可靠但步骤多)
TCP 需要先建立连接,再用 “流” 传输数据,适合需要确认的场景:
java
运行
// TCP服务器:先等电话(连接),再聊天
import java.io.*;
import java.net.*;
public class TCPServer {
public static void main(String[] args) throws IOException {
// 1. 准备电话(ServerSocket),绑定8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println(“TCP服务器启动,等待客户端连接…”);
// 2. 接电话(阻塞,直到有人打来)
Socket clientSocket = serverSocket.accept();
System.out.println(“客户端已连接:” +
clientSocket.getInetAddress());
// 3. 准备“听筒”(读客户端消息)和“话筒”(发消息给客户端)
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())
);
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true
);
// 4. 聊天循环:收到消息就回复
String message;
while ((message = in.readLine()) != null) {
System.out.println(“收到客户端:” + message);
out.println(“服务器回复:” + message); // 回复消息(确认收到)
// 输入“再见”就结束聊天
if (message.equals(“再见”)) {
break;
}
}
// 5. 挂电话(关闭连接)
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
}
java
运行
// TCP客户端:拨号打电话,开始聊天
import java.io.*;
import java.net.*;
public class TCPClient {
public static void main(String[] args) throws IOException {
// 1. 拨号(连接服务器)
Socket socket = new Socket(“localhost”, 8888);
System.out.println(“已连接服务器,可以聊天了(输入“再见”结束)”);
// 2. 准备“话筒”(发消息)和“听筒”(听回复)
PrintWriter out = new PrintWriter(
socket.getOutputStream(), true
);
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream())
);
BufferedReader userInput = new BufferedReader(
new InputStreamReader(System.in)
);
// 3. 聊天循环:输入消息并发送,等待回复
String message;
while ((message = userInput.readLine()) != null) {
out.println(message); // 发消息给服务器
System.out.println(in.readLine()); // 等服务器回复
// 输入“再见”就结束
if (message.equals(“再见”)) {
break;
}
}
// 4. 挂电话
out.close();
in.close();
userInput.close();
socket.close();
}
}
TCP 运行效果:
plaintext
// 服务器端
TCP服务器启动,等待客户端连接…
客户端已连接:/127.0.0.1
收到客户端:你好
收到客户端:在吗
收到客户端:再见
// 客户端
已连接服务器,可以聊天了(输入“再见”结束)
你好
服务器回复:你好
在吗
服务器回复:在吗
再见
服务器回复:再见
特点:消息一条接一条,服务器肯定收到,还会回复确认,就像打电话一样靠谱。
2. UDP Socket 编程:像发传单一样传消息(快但简单粗暴)
UDP 不用连接,直接打包发数据,适合追求速度的场景:
java
运行
// UDP服务器:等传单(数据包),收到就打印
import java.net.*;
public class UDPServer {
public static void main(String[] args) throws Exception {
// 1. 准备“收传单的箱子”(DatagramSocket),绑定9999端口
DatagramSocket socket = new DatagramSocket(9999);
System.out.println(“UDP服务器启动,等待消息…”);
// 2. 准备“装传单的袋子”(缓冲区)
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3. 循环收传单(阻塞,等消息)
while (true) {
socket.receive(packet); // 收到一个数据包
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println(“收到消息:” + message);
// 收到“退出”就停止
if (message.equals(“退出”)) {
break;
}
}
// 4. 关闭箱子
socket.close();
}
}
java
运行
// UDP客户端:直接发传单(数据包),不管对方收没收到
import java.net.*;
import java.io.*;
public class UDPClient {
public static void main(String[] args) throws Exception {
// 1. 准备“发传单的手”(DatagramSocket)
DatagramSocket socket = new DatagramSocket();
BufferedReader userInput = new BufferedReader(
new InputStreamReader(System.in)
);
// 2. 循环发传单
while (true) {
// 输入要发的消息
String message = userInput.readLine();
// 打包消息(指定服务器地址和端口)
byte[] data = message.getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length, InetAddress.getByName(“localhost”), 9999
);
// 发出去(不管对方收没收到)
socket.send(packet);
System.out.println(“已发送:” + message);
// 输入“退出”就停止
if (message.equals(“退出”)) {
break;
}
}
// 3. 收手
socket.close();
userInput.close();
}
}
UDP 运行效果:
plaintext
// 服务器端
UDP服务器启动,等待消息…
收到消息:Hello
收到消息:UDP真快
收到消息:退出
// 客户端
Hello
已发送:Hello
UDP真快
已发送:UDP真快
退出
已发送:退出
特点:客户端发完就走,不用等服务器回复,代码简单,速度快 —— 但如果服务器没启动,客户端也不知道消息丢了。
四、编程时怎么选?记住 3 个场景口诀
不用死记硬背,根据你的需求对号入座:
“丢了就出事”—— 选 TCP:
传文件(丢一块就损坏);
登录注册(账号密码不能丢);
即时聊天(不能漏消息,不然对话乱套)。
“卡了更要命”—— 选 UDP:
游戏操作(角色移动、攻击,卡 0.1 秒比丢个指令还糟);
直播弹幕(丢一两条弹幕,观众几乎没感觉);
物联网传感器(温度、湿度数据,偶尔丢一个不影响整体趋势)。
“想兼顾?自己加保障”:
有些场景用 UDP 但怕丢数据,可以在代码里自己加 “确认机制”—— 列如客户端发消息时带编号,服务器收到后回复编号,客户端没收到回复就重发。相当于 “用 UDP 的壳,加了 TCP 的魂”。
互动话题
你用 Socket 写过什么程序?是聊天工具、游戏还是文件传输?有没有遇到过 TCP 太卡或 UDP 丢包的问题?最后是怎么解决的?评论区说说你的经历,也聊聊你觉得哪种协议的代码更难写~



