一、 网络基础概念
1.网络的定义与目的
-
定义 :将具有独立功能的多台计算机通过通信设备与线路连接起来,在网络软件和协议的管理协调下,实现资源共享 和信息传递的系统。
-
目的 :进行网络编程,开发基于网络通信的应用程序。
2. IP地址 (Internet Protocol Address)
作用:网络设备的唯一逻辑标识,用于定位和寻址。
分类:
IPv4 :32位地址,点分十进制表示(如 192.168.1.1
),地址池近乎枯竭。
IPv6 :128位地址,十六进制表示(如 2001:0db8::1
),解决IPv4地址不足问题。
查看命令 :Linux/macOS: ifconfig,
Windows: ipconfig
连通性测试 :ping <IP或域名>
3. 端口 (Port) 与端口号 (Port Number)
端口:设备与外界通信交流的出口,是数据传输的通道。
端口号:用于标识端口的整数(0-65535)。
为什么需要端口 :IP地址只能定位到设备,端口号才能指定设备上具体的应用程序(进程)。
分类:
知名端口 (Well-known Ports):0-1023,分配给系统核心服务(如HTTP:80, HTTPS:443, SSH:22, FTP:21)。
动态端口 (Dynamic Ports):1024-65535,供普通应用程序使用。
4. URL (统一资源定位符)
作用:完整描述互联网上资源地址的字符串。
标准格式 :<协议>://<主机名>:<端口号>/<路径>?<查询参数>#<片段锚点>
示例解析 :https://www.example.com:8080/api/users?id=1001#profile
协议(Scheme): https
主机名(Host): www.example.com
端口(Port): 8080
(HTTPS默认443,可省略)
路径(Path): /api/users
查询字符串(Query): ?id=1001
片段(Fragment): #profile
(客户端使用,不发送到服务器)
概念 | 说明 |
---|---|
IP地址 | 网 络中设备的唯一逻辑地址,用于标识和定位设备。 |
IPv4 | 32位地址,点分十进制表示(如 192.168.1.1 ),约42亿个地址。 |
IPv6 | 128位地址,十六进制表示(如 2001:0db8::1 ),解决IPv4地址耗尽问题。 |
URL (统一资源定位符) | 用于定位互联网上资源的地址。完整格式:协议://域名:端口/路径?查询参数#锚点 |
二、同源与跨域 (Same-Origin vs. Cross-Origin)
特性 | 同源 (Same-Origin) | 跨域 (Cross-Origin) |
---|---|---|
定义 | 协议、域名、端口完全相同 | 协议、域名、端口有任一不同 |
示例 | https://example.com/app 与 https://example.com/api |
https://example.com 与 http://example.com (协议不同) |
访问权限 | 完全访问 DOM、Cookie、AJAX 请求 | 默认禁止 访问,受同源策略限制 |
解决方案 | 无需特殊处理 | CORS (跨域资源共享)、JSONP、代理服务器、WebSocket |
同源策略 (SOP):浏览器的核心安全机制,防止恶意网站窃取另一个网站的数据。
三、Socket 套接字及使用场景
方面 | 说明 |
---|---|
是什么 | 网络通信的端点(Endpoint),是应用程序通过网络协议进行数据交互的接口。 |
比喻 | IP地址是地址,端口是门牌号,Socket就是连接两扇门的电话线。 |
使用场景 | 任何网络通信!包括Web服务(HTTP/HTTPS)、邮件(SMTP/POP3)、文件传输(FTP)、数据库连接、实时通信(游戏、聊天)等。 |
本质 | 封装了底层网络协议(如TCP/IP)的复杂操作,为程序员提供简单的API(如 send() , recv() , connect() )。 |
四、TCP 与 UDP 的特点与区别
特性 | TCP (传输控制协议) | UDP (用户数据报协议) |
---|---|---|
连接性 | 面向连接 (需三次握手) | 无连接 (直接发送) |
可靠性 | 可靠传输 (确认、重传、校验) | 不可靠传输 (可能丢失、乱序) |
数据顺序 | 保证数据顺序 | 不保证数据顺序 |
速度/开销 | 速度慢,开销大(有控制机制) | 速度快,开销小 (无控制机制) |
流量控制 | 有 (滑动窗口) | 无 |
应用场景 | 网页浏览(HTTP/S)、邮件(SMTP)、文件传输(FTP)、远程登录(SSH) | 视频流、语音通话(VoIP)、在线游戏、DNS查询、直播 |
比喻 | 打电话:需要接通,确认对方听到,有条理地对话。 | 对讲机/发传单:直接说,不管对方是否收到,可能听不清。 |
五、TCP的可靠传输机制与连接管理
1 可靠传输机制
确认应答 (ACK):接收方收到数据后必须回复确认消息。
超时重传 (Retransmission):发送方在一定时间内未收到ACK,会重发数据。
序列号与确认号:为每个字节编号,解决乱序和重复问题。
流量控制 (Flow Control):通过滑动窗口机制,防止发送过快导致接收方缓冲区溢出。
拥塞控制 (Congestion Control):通过慢启动、拥塞避免等算法,避免网络过载。
2 TCP 三次握手与四次挥手
三次握手 (建立连接 - 我要和你打电话)
-
SYN :客户端 -> 服务器。"你好,我能和你连接吗?" (
SYN_SENT
) -
SYN-ACK :服务器 -> 客户端。"收到,我可以连接,你准备好了吗?" (
SYN_RCVD
) -
ACK :客户端 -> 服务器。"好的,我准备好了,开始通信吧!" (
ESTABLISHED
)
" TCP三次握⼿" 是指在计算机⽹络中,TCP协议(传输控制协议)建⽴连接时所进⾏的⼀种过程。具 体来说,它包含以下三个步骤:
-
第⼀次握⼿:客户端发送⼀个带有SYN(同步序列编号)标志的TCP报⽂到服务器,表示请求建 ⽴连接。此时客户端进⼊SYN-SENT(同步已发送)状态。
-
第⼆次握⼿:服务器收到客户端的SYN报⽂后,会回复⼀个带有SYN和ACK(确认)标志的TCP 报⽂给客户端,其中ACK是对客户端SYN报⽂的确认,同时服务器⾃⼰也发送⼀个SYN报⽂,表 示⾃⼰也想建⽴连接。此时服务器进⼊SYN-RCVD(同步已接收)状态。
-
第三次握⼿:客户端收到服务器的SYN+ACK报⽂后,再发送⼀个带有ACK标志的TCP报⽂给服 务器,对服务器的SYN报⽂进⾏确认。此时客户端进⼊ESTABLISHED(已建⽴连接)状态,服 务器收到客户端的ACK报⽂后,也进⼊ESTABLISHED状态,⾄此TCP连接建⽴完成。
这种三次握⼿的过程可以有效防⽌出现错误的连接建⽴,确保双⽅都准备好进⾏数据传输。
四次挥手 (断开连接 - 我要挂电话了)
-
FIN :客户端 -> 服务器。"我说完了,要挂电话了。" (
FIN_WAIT_1
) -
ACK :服务器 -> 客户端。"等等,我还没说完..." (
CLOSE_WAIT
/FIN_WAIT_2
) -
FIN :服务器 -> 客户端。"好了,我也说完了,可以挂了。" (
LAST_ACK
) -
ACK :客户端 -> 服务器。"好的,再见!" (
TIME_WAIT
-> 等待后CLOSED
)
" TCP四次挥⼿" 是指TCP协议在断开连接时所进⾏的四次交互过程。具体如下:
-
第⼀次挥⼿:主机A(客户端)向主机B(服务器)发送⼀个FIN(Finish)报⽂,表示A想要关闭 连接,进⼊" FIN_WAIT_1" 状态。这个FIN报⽂的序号是seq = u,u是⼀个随机的序号值。
-
第⼆次挥⼿:主机B收到A的FIN报⽂后,会发送⼀个ACK(Acknowledgment)报⽂给A,表示B 已经收到A的关闭连接请求。这个ACK报⽂的序号是seq = v,确认号是ack = u + 1,表示B确认 了A的FIN报⽂。此时,B进⼊" CLOSE_WAIT" 状态,⽽A进⼊" FIN_WAIT_2" 状态。
-
第三次挥⼿:主机B在处理完⾃⼰的事务后,也会向主机A发送⼀个FIN报⽂,表示B也想要关闭 连接。这个FIN报⽂的序号是seq = w,确认号是ack = u + 1。此时,B进⼊" LAST_ACK" 状态。
-
第四次挥⼿:主机A收到B的FIN报⽂后,会发送⼀个ACK报⽂给B,表示A已经收到B的关闭连接 请求。这个ACK报⽂的序号是seq = u + 1,确认号是ack = w + 1。此时,A进 ⼊" TIME_WAIT" 状态,等待2MSL(Maximum Segment Lifetime)时间后,如果没有收到B的 任何报⽂,A就正式关闭连接,进⼊" CLOSED" 状态。⽽B在收到A的ACK报⽂后,也进 ⼊" CLOSED" 状态,完成整个断开连接的过程。
TCP四次挥⼿的⽬的是确保双⽅在断开连接时能够安全、可靠地完成数据传输,并且双⽅都能明确知 道对⽅已经关闭了连接
为什么挥手多一次?
因为TCP连接是全双工的,每一方向必须单独关闭。
六、TCP 网络应用程序开发总结
1 TCP 发送数据基本流程 (客户端)

代码:
python
graph TD
A[创建Socket对象] --> B[建立连接 connect]
B --> C[发送数据 send]
C --> D[关闭连接 close]
2 TCP 接收数据基本流程 (服务端)

代码:
python
graph TD
A[创建Socket对象] --> B[绑定IP和端口 bind]
B --> C[设置监听 listen]
C --> D[等待连接 accept<br>阻塞直到客户端连接]
D -- 连接成功, 返回新Socket --> E[接收数据 recv]
E --> F[发送响应 send]
F --> G[关闭客户端连接 close]
G --> D
3 核心开发流程
步骤 | 客户端 (Client) | 服务器端 (Server) |
---|---|---|
1. 创建Socket | socket.socket() |
socket.socket() |
2. 绑定地址 | (通常系统自动分配) | 必须 .bind((host, port)) |
3. 建立连接 | 主动 .connect((server_ip, server_port)) |
被动 .listen(backlog) |
4. 接受连接 | - | .accept() -> 返回新Socket |
5. 数据传输 | .send() / .recv() |
使用accept返回的新Socket 进行 .send() / .recv() |
6. 关闭连接 | .close() |
先关新Socket,再关监听Socket |
4 关键注意事项
-
字节流编码 :网络传输的是字节(
bytes
)。发送前需.encode('utf-8')
,接收后需.decode('utf-8')
。 -
监听Socket vs 通信Socket:
-
监听Socket :仅用于接受新连接 (
accept()
),不能收发数据。 -
通信Socket :
accept()
返回的新Socket,用于与特定客户端进行数据通信。
-
-
多客户端并发 :默认的
accept()
->recv()
->send()
是串行的。处理多客户端必须使用 多线程 、多进程 或 I/O多路复用 (如selectors
模块)。 -
连接状态判断 :如果
recv()
返回空数据(长度为0的bytes),则表示对方已关闭连接。 -
端口复用:服务器重启时避免"Address already in use"错误。
python
# 在bind()之前设置
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
示例:
编写一个TCP回声服务器和客户端程序:
· 服务器监听本地端口8888
· 客户端连接到服务器后,用户可以输入任意字符串
· 服务器将接收到的消息原样返回给客户端
· 客户端显示服务器返回的消息
· 当用户输入"quit"时,客户端和服务器都应正常关闭连接
要求:
· 服务器能够同时处理多个客户端连接(使用多线程或多进程)
· 客户端和服务器都需要有适当的错误处理
· 代码结构清晰,有必要的注释
服务端代码(server.py):
python
import threading
import socket
# 关于对处理客户端的连接
def handle(new_socket, ip_port):
print(f"新的连接:{ip_port}")
try:
while True:
data = new_socket.recv(1024).decode('utf-8')
# 判断是否收到空数据
if not data:
print(f"客户端 {ip_port} 断开连接")
break
# 打印收到的消息和客户端的信息
print(f"收到来自 {ip_port} 的消息: {data}")
# 检测是否有退出的请求
if data == "quit":
print(f"客户端 {ip_port} 请求退出连接")
new_socket.send("服务器连接关闭".encode("utf-8"))
break
# 发送从客户端传过来的信息
new_socket.send(data.encode('utf-8'))
# 捕获异常
except Exception as e:
print(f"客户端 {ip_port}: 发生错误 {e}")
finally:
new_socket.close()
print(f"与客户端 {ip_port} 的连接已断开")
# 启动tcp的服务端函数
def start_server(host='127.0.0.1', port=8080):
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server_socket.bind((host, port))
# 开始接听连接
server_socket.listen(5)
print(f"服务器启动, 监听: {host}:{port}")
print("等待客户端连接...")
while True:
new_socket, ip_port = server_socket.accept()
client_thread = threading.Thread(target=handle, args=(new_socket, ip_port))
client_thread.daemon = True
client_thread.start()
print(f"活跃线程数: {threading.active_count()-1}")
# 捕获异常
except Exception as e:
print(f"服务器错误: {e}")
finally:
server_socket.close()
print("服务器已关闭")
if __name__ == '__main__':
start_server()
客户端代码(client.py):
python
import socket
# 启动客户端的函数
def start_client(host='127.0.0.1', port=8080):
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client_socket.connect((host, port))
print(f'已连接到服务器 {host}:{port}')
print("输入消息发送到服务器, 发送quit退出")
while True:
message = input("请输入: ")
client_socket.send(message.encode('utf-8'))
if message == 'quit':
break
data = client_socket.recv(1024).decode('utf-8')
print(f"服务器的回复: {data}")
except Exception as e:
print(f"客户端错误: {e}")
finally:
client_socket.close()
print("连接已关闭")
if __name__ == '__main__':
start_client()

六、 总结
网络基础 :理解 IP地址 (定位设备)、端口 (定位应用)、Socket (通信工具) 是网络编程的基石。
协议选择 :根据应用场景在可靠但慢的TCP 和快速但不可靠的UDP之间做出权衡。
TCP精髓 :其可靠性 源于复杂的机制(握手、挥手、确认、重传、控制),其开发流程围绕"建立连接->传输->关闭连接"展开。
开发关键 :严格遵循开发流程,深刻理解字节编码 、双Socket分工 和多客户端并发处理,是写出稳定高效TCP程序的关键。