欢迎光临
我们一直在努力

【从0开始学习计算机网络】| TCP与UDP详解

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

🎬精选专栏传送门:

❄️《数据结构》 ❄️《AI与Agent那些事》

❄️《从0开始学计算机网络》 ❄️《后端开发》

前言:

你上个月是不是也遇到过一次:给朋友寄了个文件,快递员放楼下快递柜就走了,连个电话都没打。你朋友第二天才看到取件码,气得不行。

但换个场景——你寄的是合同原件,快递员非要你当面签收,还让你报身份证号。你嫌麻烦,可又觉得踏实。

网络世界里,数据就是这么送的。而负责“送数据”的两种主要方式,就是 TCP 和 UDP。一个像那个不管不顾的快递员,一个像那个非要签收的快递员。

今天就把这俩讲明白。

先搞清楚:网络里“发消息”到底是怎么回事

在聊 TCP 和 UDP 之前,得先知道网络里数据是怎么从一台电脑到另一台电脑的。这里没有任何高深的东西。

假设你要给朋友发一个 10MB 的照片文件。网络传输有个特点:它不喜欢一次性搬大块头。就像搬家不会把整个衣柜原封不动抬走,而是拆成板子、装进箱子、贴上标签再运。网络也一样,会把你的大文件切成一小块一小块,每块单独发送。

这一小块一小块的数据,专业术语叫数据包(Packet)。

每个数据包上面都写着两样关键信息:

1. IP 地址——这就相当于收件人的门牌号。比如 `192.168.1.100`,这串数字在全世界范围内唯一标识一台设备。你朋友的电脑有一个,他手机也有一个,他家路由器也有一个。

2. 端口号——光有门牌号还不够。你朋友的电脑上可能同时开着微信、浏览器、游戏,数据包到了他家门口,得知道该交给哪个程序。端口号就像是门牌号里的“房间号”。比如 80 端口通常是网页服务,443 是加密网页服务,你自己写的程序可以随便用一个没被占用的端口。

所以,数据包的完整地址应该是:IP 地址 + 端口号,合起来叫套接字(Socket)。不过这个术语今天用不上,你只要记住:发数据 = 把数据切成块,每块写上对方的 IP 和端口,然后扔到网络里。

问题来了:扔出去之后,怎么保证对方能收到?这就是 TCP 和 UDP 分道扬镳的地方。

UDP——放下就跑的快递员

UDP(User Datagram Protocol,用户数据报协议)这个快递员,风格就是:包裹放下,转身就走,爱签不签。

你寄一张明信片,扔进邮筒,然后呢?没有人会通知你“明信片已送达”,也不会有人告诉你“对方收到没”。丢了就丢了,你甚至不知道它丢了。

UDP 就是这个逻辑。发数据包的时候,它不会先跟对方打个招呼,也不管对方在不在线,直接把数据包扔进网络里。对方收到了就收到了,没收到也不会重发。

专业术语叫无连接——发送之前不需要建立连接。以及不可靠——不保证送达,不保证顺序,不保证不丢包。

看代码可能更直观。这是 Python 里用 UDP 发消息的最简示例:

import socket

# 创建 UDP socket,SOCK_DGRAM 就是 UDP 的意思

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 目标地址:IP + 端口

target = ("192.168.1.100", 8888)

# 直接发,不需要先连接,不需要确认对方在不在

sock.sendto(b"Hello, UDP!", target)

# 完事。对,就这么简单,没有握手,没有确认。

```

接收端就更简单了:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

sock.bind(("0.0.0.0", 8888))  # 监听所有网卡的 8888 端口

while True:

    data, addr = sock.recvfrom(1024)  # 收到数据包和来源地址

    print(f"收到来自 {addr} 的消息: {data.decode()}")

```

你发现没有,整个过程没有“你一句我一句”的确认环节。发完就走,干净利落。

那这种“不靠谱”的协议有什么用?用处大了。

视频通话。你和朋友视频聊天,画面一帧一帧传过来。如果某一帧丢了,最合理的策略是什么?丢掉就丢掉了,下一帧马上就来。如果为了补一帧画面而停下来等待重传,那整个视频会卡成 PPT。人眼对短暂的画面缺失不敏感,但对卡顿极其敏感。

直播同理。主播说了一句话,中间丢了一秒的声音,观众根本察觉不到。但如果因为丢包而停下来缓冲,那体验就是灾难。

在线游戏也是。你操控角色往前走,这个操作指令必须尽快发到服务器。如果走 UDP 丢了几个包,最多角色卡顿一下;如果走 TCP 因为等待重传而延迟半秒,你可能已经被对面击杀了。

一句话总结 UDP 的场景:可以容忍少量丢失,但绝对不能容忍延迟。

TCP——必须签收的快递

TCP(Transmission Control Protocol,传输控制协议)是另一个极端。它像寄贵重物品的快递:先打电话确认你在家,然后上门,你当面签收,签完字还要拍个照存档。

TCP 的第一个特点是面向连接——在正式传数据之前,双方先“打个招呼”,确认彼此都在线,然后才开工。

这个打招呼的过程,专业术语叫三次握手(Three-way Handshake)。用大白话说就是:

1. 你(客户端)对服务器说:“喂,你在吗?我想传数据。”(这叫 SYN)

2. 服务器回你:“在的,在的,我准备好了,可以开始。”(这叫 SYN-ACK)

3. 你再说:“好,收到,那我开始了。”(这叫 ACK)

三句话说完,连接建立,开始传数据。

那你可能会问:为什么非得三次?两次行不行?比如你发“在吗”,对方回“在”,不就算确认了吗?

不行。因为网络可能丢包。如果对方回的“在”丢了,你以为对方不在线,就不会开始发数据。三次握手的本质是:双方都要确认“我能收到你,你也能收到我”。第三次的 ACK 就是让服务器知道“客户端确实收到了我的回复”。这样就确保了两边都确认了对方在线。

连接建立之后,TCP 还要保证可靠传输。可靠体现在三件事:

第一,确认机制。每收到一个数据包,接收方就回一个“收到了”的确认包(ACK)。就像快递员等你签收,签了字才算数。

第二,重传机制。如果发送方发出去一个包,等了一会儿没收到确认,就默认丢了,重新发一遍。就像快递员打电话给你没打通,过一会儿再打。

第三,顺序保证。数据包走的路径可能不一样,到达的顺序可能是乱的。TCP 会给每个包编上序号,接收方按序号重新排好,再交给上层应用。就像快递单上有编号,你收到的包裹即使乱序,也能按编号整理好。

Python 里用 TCP 发送数据大概是这样的:

import socket

# 创建 TCP socket,SOCK_STREAM 就是 TCP

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# TCP 必须首先建立连接——这就是三次握手

sock.connect(("192.168.1.100", 8888))

# 连接建立后,可以直接发送数据

sock.sendall(b"Hello, TCP!")

# 等待对方的确认回复

response = sock.recv(1024)

print(f"对方确认收到: {response.decode()}")

sock.close()

```

接收端:

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.bind(("0.0.0.0", 8888))

sock.listen(5)  # 开始监听,最多允许 5 个连接排队

while True:

    conn, addr = sock.accept()  # 接受连接——三次握手完成

    data = conn.recv(1024)

    print(f"收到来自 {addr} 的消息: {data.decode()}")

    conn.sendall(b"ACK: 我收到了!")

    conn.close()

```

同样是一段代码,对比 UDP 那个版本,你发现关键差异了吗?TCP 要先 `connect()`,这就是三次握手。发完数据还要等对方回应。UDP 没有这一切。

TCP 适合什么场景?一点都不能丢的场景。

网页浏览。你打开一个网页,HTML、CSS、JavaScript、图片,任何一个文件缺失都会导致页面显示错乱。所以浏览器和服务器之间用 TCP。

文件下载。下载一个安装包,哪怕只缺一个字节,这个文件就是坏的,装不上。必须用 TCP。

邮件。邮件内容一个字符都不能丢。发出去的邮件如果少了一段,那麻烦大了。TCP。

游戏里的登录系统、交易系统,也基本都是 TCP。因为这些操作必须要可靠,你不想登录的时候账号信息丢了导致上不了号。

那到底怎么选?一张表看懂

到了这里,你应该已经能判断了。我给你整理一张对比表:

| 维度 | TCP | UDP |

| 连接 | 需要先建立连接(三次握手) | 无连接,直接发 |

| 可靠性 | 可靠:确认、重传、保序 | 不可靠:可能丢包、乱序 |

| 速度 | 慢(有确认和重传的开销) | 快(没有额外开销) |

| 数据量 | 适合大文件传输 | 适合实时小数据 |

| 典型场景 | 网页、文件下载、邮件、登录 | 视频通话、直播、游戏 |

看视频用哪个?你在视频网站上点开一个视频,这个场景其实两个都有。视频文件本身是通过 TCP 下载的(一次下载完,之后本地播放)。但如果你在看直播,那必须是 UDP。区别在于:录播视频可以慢慢下载,直播必须实时。

发微信消息用哪个?微信文字消息是 TCP。你发“在吗”,对方必须收到,不能丢。但微信语音通话是 UDP——实时通话,丢几帧语音听不出来,但卡顿完全不能忍。

打王者荣耀用哪个?游戏本身的操作指令走 UDP(要求低延迟),但登录验证、购买皮肤这些操作走 TCP(要求可靠)。一个游戏里两种协议混着用,很正常。

下载大文件用哪个?必须是 TCP。你下载一个 2GB 的压缩包,中间丢了一个数据包,整个文件就损坏了。TCP 的重传机制在这里就是生命线。

核心判断标准:如果数据丢了会导致严重后果,选 TCP;如果延迟比丢包更致命,选 UDP。

没有谁更好,只有谁更合适。TCP 是“稳”,UDP 是“快”。你在两者之间选,本质上是在选“你能接受什么代价”。

小结

TCP 和 UDP 是网络传输的两种基本方式,你可以理解为两个性格完全不同的快递员:

– UDP:放下就跑,不确认、不重传、不保序。适合视频通话、直播、游戏——这些场景能容忍少量丢包,但绝对不能容忍延迟。

– TCP:先打招呼(三次握手),每步都确认,丢了就重传。适合网页、文件下载、邮件——这些场景一个字节都不能少,慢一点没关系。

下一步,如果你装了 Python,可以把上面两个代码示例跑一下。先跑 UDP 的,再跑 TCP 的,感受一下“无连接”和“面向连接”的差异。你会发现 TCP 那个 `connect()` 和等回复的过程,就是它可靠性的来源。

赞(0)
未经允许不得转载:171主机测评 » 【从0开始学习计算机网络】| TCP与UDP详解
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址