Socket 编程时,TCP 和 UDP 到底该选谁? “稳如老狗”,“快如闪电”

写网络编程时,你是不是也纠结过:同样是 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 丢包的问题?最后是怎么解决的?评论区说说你的经历,也聊聊你觉得哪种协议的代码更难写~

© 版权声明

相关文章

暂无评论

none
暂无评论...