人人都能学编程
English 开始学习
核心 · 计算机网络第 3 课 / 共 6 课免费阅读

TCP、UDP 与端口 · 计算机网络

在不可靠的网络上,两个程序怎么进行可靠的对话?

课程目录

为什么需要它

数据包时时刻刻都在丢失、重复、乱序。TCP 把这些都藏起来,给程序一个可靠的数据流;UDP 为了速度不做这些保证。端口让一台机器能同时运行很多服务。每一个「connection refused(连接被拒绝)」「connection timed out(连接超时)」的错误,都和它们有关。

直觉理解

地址找到机器;端口(0–65535)找到机器上的程序。常见的:22 SSH、53 DNS、80 HTTP、443 HTTPS、5432 PostgreSQL。

TCP 以三次握手开始:SYN(「能聊吗?」)、SYN-ACK(「能,你听得到我吗?」)、ACK(「听得到」)。之后每块数据都有编号(序列号);接收方确认收到了什么,把数据按顺序拼回去,发送方会重发没被确认的部分。

UDP 只管发。适合「晚到的数据反正没用」的场景:视频通话、游戏、DNS 查询。

定义

端口 Port

A number from 0 to 65535 that picks one program on a machine. A server listens on a port; a client connects to address:port.
0 到 65535 之间的一个数,用来选中机器上的某个程序。服务器在某个端口上监听;客户端连接 地址:端口。

TCP 与 UDP

TCP: connection, ordering, retransmission, flow control. UDP: single datagrams, no guarantees, less delay.
TCP:有连接、保证顺序、会重传、有流量控制。UDP:单个数据报,不做保证,延迟更低。

示例

把数据块按顺序拼回去

动手试试

数据段乱序到达,还有一个重复了。序列号能同时解决这两个问题。

arrived = [(3, "lo w"), (1, "hel"), (4, "orld"), (3, "lo w"), (2, "")]
received = {}
for seq, data in arrived:
    if seq in received:
        print("duplicate", seq, "ignored")
        continue
    received[seq] = data
message = "".join(received[s] for s in sorted(received))
print(message)
逐步执行
  1. L4这个编号已经见过了:丢掉。duplicate 3 ignored
  2. L8按序列号排序,而不是按到达顺序。
  3. L9顺序对了,也没有重复。hello world

缺了哪一块?

动手试试

接收方确认它期望的下一个编号。发送方从那里开始重发。

got = {1, 2, 4, 5}
expected = 1
while expected in got:
    expected += 1
print("ACK", expected)
逐步执行
  1. L31 和 2 到了,3 没到。
  2. L5「下一个请发 3」:4 和 5 要等 3 到了才能交给程序。ACK 3

常见错误

被拒绝和超时不一样

连接被拒绝:机器回应了,但那个端口上没有程序在监听(服务没开、端口错了)。连接超时:完全没有回应(防火墙、地址错了、机器关了)。

以为 TCP 总是更好

重发一帧已经来不及显示的视频画面,只会让通话更卡。实时流量往往更适合 UDP。

小测验

1. 机器上跑着一个网页服务器,但 `curl http://host:8080` 显示「connection refused」。最可能的原因?

  1. A8080 端口上没有程序在监听
  2. BDNS 坏了
  3. C网线拔了
查看答案

答案:A

被拒绝说明机器回应了:能连上机器,只是那个端口没有程序接受连接。

2. 这段代码会输出什么?

handshake = ["SYN", "SYN-ACK", "ACK"]
for i, msg in enumerate(handshake, 1):
    sender = "client" if msg != "SYN-ACK" else "server"
    print(i, sender, msg)
  1. A
    1 client SYN
    2 server SYN-ACK
    3 client ACK
  2. B
    1 server SYN
    2 client SYN-ACK
    3 server ACK
  3. C
    1 client SYN
    2 client SYN-ACK
    3 server ACK
查看答案

答案:A

客户端发起,服务器回应,客户端确认。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出重组

    准确写出这段程序的输出。

  2. 改需求说出服务名

    service(port) 应该说出常见端口的服务名。加上 HTTPS(443)、SSH(22)和 PostgreSQL(5432,返回 "postgres"),其他端口返回 "unknown",而不是崩溃。

  3. 从零写累积确认

    写函数 next_ack(received):参数是已到达的序列号列表(顺序任意,可能有重复,从 1 开始),返回接收方应该请求的下一个编号:缺失的最小正整数。

在互动课里练这一课

打开互动课,这些例子都能直接改、直接运行,练习题提交马上判题。免费开始,不用注册。

互动课按顺序解锁:前面的课还没学,会先带你到课程地图。

本课术语

术语中文英文定义
Port number端口号A number that selects a program on a machine, such as 443 for HTTPS.
TCP传输控制协议A reliable, ordered byte stream between two programs.
UDP用户数据报协议Single messages with no delivery guarantee and little delay.
Three-way handshake三次握手SYN, SYN-ACK, ACK: how a TCP connection starts.