1. 网络编程基础回顾:TCP/IP协议栈、Socket编程基础、客户端-服务器模型
好,咱们正式开始。第一节课,我不会一上来就扔一堆晦涩的概念。
网络编程这东西,说白了就是让两台机器能“说上话”。你想想看,你在浏览器里输入一个网址,几毫秒后页面就出来了——这背后就是网络编程在干活。我当年刚入行时,总觉得这玩意儿很玄乎,直到亲手写了一个聊天程序,才真正理解“数据是怎么从A跑到B的”。
1.1 TCP/IP协议栈:数据是怎么“打包”的?
先聊协议栈。很多人一听到“七层模型”、“四层模型”就头大。其实你不用背,记住一个核心就行:每一层只关心自己的事,下层为上层服务。
我习惯把TCP/IP协议栈简化成四层来看:
| 层级 | 典型协议 | 核心职责 | 我眼中的比喻 |
|---|---|---|---|
| 应用层 | HTTP、FTP、WebSocket | 定义数据格式和业务逻辑 | 写信的内容 |
| 传输层 | TCP、UDP | 端到端可靠传输 / 端口寻址 | 信封上的收件人 |
| 网络层 | IP | 路由选择、IP寻址 | 信封上的地址 |
| 网络接口层 | 以太网、Wi-Fi | 物理介质上的比特流传输 | 邮递员的交通工具 |
嗯,这里要注意:TCP和UDP的区别是面试高频题,也是你后面理解粘包拆包的基础。
- TCP:面向连接、可靠、有序、有流量控制。代价是慢一点,有额外开销。
- UDP:无连接、不可靠、无序、无流量控制。优点是快,适合实时场景。
核心记忆点:TCP保证你发的数据“一定到、不乱序、不重复”;UDP只管“扔出去,爱到不到”。
我在项目中遇到过一个问题:用UDP传文件,结果丢包率高达30%,文件永远打不开。后来换成TCP,虽然慢了点,但至少能用了。所以选协议时,一定要想清楚你的场景是“要快”还是“要稳”。
1.2 Socket编程基础:你写的代码怎么跟网卡打交道?
Socket,中文叫“套接字”。名字挺拗口,其实它就是操作系统提供的一个编程接口。你通过它告诉内核:“我要发数据到某个IP的某个端口”。
我个人习惯把Socket理解成一个“管道”。你往管道里写数据,内核帮你封装成TCP段、IP包,最后扔到网线上。对面从管道里读数据,一层层解包,拿到原始内容。
Python里用socket模块,代码非常简洁。我带你走一遍最核心的流程:
服务端(Server)
import socket
# 1. 创建Socket对象
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定IP和端口
server.bind(('0.0.0.0', 8888))
# 3. 开始监听
server.listen(5)
print('服务端已启动,等待连接...')
# 4. 接受客户端连接
conn, addr = server.accept()
print(f'客户端 {addr} 已连接')
# 5. 接收数据
data = conn.recv(1024)
print(f'收到: {data.decode()}')
# 6. 发送响应
conn.send(b'Hello, Client!')
# 7. 关闭连接
conn.close()
server.close()
客户端(Client)
import socket
# 1. 创建Socket对象
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 连接服务端
client.connect(('127.0.0.1', 8888))
# 3. 发送数据
client.send(b'Hello, Server!')
# 4. 接收响应
data = client.recv(1024)
print(f'收到: {data.decode()}')
# 5. 关闭连接
client.close()
避坑指南:我曾经在服务端忘记调用 bind(),结果程序一直报错“Address already in use”。后来养成习惯,每次启动前先检查端口是否被占用。另外,recv(1024) 里的1024是缓冲区大小,不是一次只能收1024字节——这个后面讲粘包时会细说。
1.3 客户端-服务器模型:谁主动,谁被动?
这个模型其实很简单:客户端主动发起请求,服务端被动等待并处理请求。
你想想看,你每次打开,客户端就去连腾讯的服务器。服务器不会主动连你的手机——因为你的IP是动态的,服务器根本不知道你在哪。这就是典型的C/S模型。
我画了一张图,帮你理清整个流程:
这个图里,我特意把三次握手和请求/响应分开了。你注意看:connect() 触发三次握手,握手完成后,send() 和 recv() 才开始传真正的业务数据。
曾经踩过的坑:我在一个项目里,客户端连续调了两次 send(),服务端只调了一次 recv(),结果两次发送的数据被合并成一次收到了。这就是典型的粘包——也是咱们这门课的核心主题。别急,后面几章我会手把手带你解决它。
1.4 本章小结:你该带走什么?
好,第一节课的内容就这些。我不喜欢堆砌概念,你只要记住三件事:
- TCP/IP协议栈是分层协作的,每层只干自己的活。
- Socket是操作系统给你的“管道”,通过它跟网络打交道。
- C/S模型的核心是“客户端主动,服务端被动”。