你以为你会用requests库爬虫就算懂网络编程?看完这篇,你会发现网络编程的“灵魂”原来在这里。

在当今这个万物互联的时代,无论是你正在刷的短视频、打出的语音通话,还是复杂的分布式系统,底层都离不开网络编程。对于很多Python开发者来说,网络编程似乎总是隔着一层纱——会用requests.get(),却说不清三次握手;知道Socket,却搞不懂UDP和TCP到底该怎么选。

今天,我们就从最底层的网络模型讲起,一路杀到Python代码实战,最后再封装一个高性能的异步Web接口。这不仅是一篇教程,更是一张带你彻底搞懂Python网络编程的“藏宝图”。


01 基石篇:不懂这三要素,就别谈网络编程

在敲下第一行代码之前,我们必须先理解网络世界的“交通规则”。所有的网络通信,都离不开三大要素:IP、端口、协议

1.1 IP地址:互联网上的“门牌号”

IP地址是设备在网络中的唯一标识。就像寄快递需要地址一样,数据包也需要IP地址才能找到目标电脑。

  • IPv4与IPv6:我们现在常用的IPv4(如192.168.1.1)已经于2011年耗尽,因为它只有约42亿个地址。而IPv6拥有3.4×10³⁸个地址,理论上能给地球上每一粒沙子都分配一个IP。

  • 公网与私网:你在家里用的192.168.x.x是私网IP,只能在局域网内使用。当你访问百度时,路由器会通过NAT(网络地址转换)技术,将你的私网IP映射成公网IP,实现上网。

1.2 端口:找到那扇唯一的“门”

IP地址找到了电脑,但电脑上运行着微信、浏览器、游戏等多个程序,数据该交给谁?这就是端口的作用。它是一个逻辑地址,范围是0~65535。

  • 公认端口 (0-1023):系统保留,比如80端口给HTTP,443给HTTPS,22给SSH。

  • 动态端口 (1024-65535):当你打开一个QQ聊天窗口,系统会随机分配一个动态端口用于这次通信,关闭后端口就被释放了。

1.3 协议:大家都能懂的“语言”

协议就是通信的约定。就像中国人说中文,英国人说英语,网络设备必须遵循同一套协议才能交流。最核心的就是TCP/IP协议族

这里有一个非常重要的概念:五层网络模型

  • 应用层:你看到的HTTP、FTP、SMTP都在这一层,负责数据的具体含义。

  • 传输层:负责端到端的传输,核心协议是TCPUDP

  • 网络层:负责路由寻址,核心协议是IP

  • 数据链路层 + 物理层:负责硬件传输,比如网线、光纤。


02 核心篇:Socket——打开网络世界的“万能钥匙”

如果要把上面这些理论变成代码,我们需要一个“工具”,这个工具就是Socket(套接字)

你可以把Socket想象成一个“插座”。服务端把插座插好(绑定IP和端口),等待客户端来插上插头(连接)。在Python中,一行代码就能创建一个“插座”:

python

import socket

# TCP 套接字 (面向连接,可靠)
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# UDP 套接字 (无连接,不可靠但快)
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

2.1 UDP:追求速度的“快递小哥”

UDP(用户数据报协议)就像一个激进的快递员:他拿了包裹就走,不管对方收没收到,也不管包裹是否顺序到达。它没有连接,开销极小,速度快。

应用场景:实时性要求高的场景,比如视频直播、在线游戏、语音通话。哪怕丢一帧画面或漏一个语音包,也比等待重传导致卡顿要好。

实战代码(UDP聊天器)
UDP编程不需要建立连接,客户端直接发,服务端直接收。

python

# ---------- UDP 服务端 ----------
import socket

udp_server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_server.bind(('127.0.0.1', 8080))  # 绑定本地地址

print("UDP服务端启动,等待数据...")
while True:
    data, addr = udp_server.recvfrom(1024)  # 接收数据,同时获取对方地址
    print(f"收到来自 {addr[0]}:{addr[1]} 的消息: {data.decode('utf-8')}")
    udp_server.sendto("消息已收到".encode('utf-8'), addr)  # 回复数据

核心解析
recvfrom 和 sendto 是UDP的精髓。因为无连接,每次收发都必须带上对方的地址,就像寄信必须写邮编和收件人。

2.2 TCP:追求可靠的“电话亭”

TCP(传输控制协议)则像一个电话通话系统。在通信之前,必须先建立连接(三次握手),通信结束后断开连接(四次挥手)。它提供可靠传输:数据包丢失了会重传,顺序乱了会重排。

应用场景:网页浏览(HTTP)、文件传输(FTP)、邮件(SMTP)。这些场景数据绝对不能出错。

实战代码(TCP简易聊天)
TCP需要先建立连接。服务端需要监听,然后为每个客户端生成一个新的套接字进行通信。

python

# ---------- TCP 服务端 ----------
import socket

tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_server.bind(('127.0.0.1', 8080))
tcp_server.listen(5)  # 开始监听,最大等待连接数5

print("TCP服务端启动,等待连接...")
# 阻塞等待客户端连接,accept返回一个新的socket用于通信
client_socket, client_addr = tcp_server.accept()
print(f"客户端 {client_addr[0]}:{client_addr[1]} 已连接")

while True:
    data = client_socket.recv(1024)
    if not data:  # 如果对方断开连接,recv会返回空
        break
    print(f"收到: {data.decode('utf-8')}")
    client_socket.send("已收到".encode('utf-8'))
client_socket.close()
tcp_server.close()

核心解析
TCP服务端有两层Socket:一个是tcp_server(负责“接电话”),一个是client_socket(负责“通话”)。这体现了TCP面向连接的特性。

对比总结

  • TCP:可靠、有序、面向连接。适合网页、文件传输。代码上多了listenaccept

  • UDP:不可靠、无序、无连接。适合直播、游戏。代码上直接sendtorecvfrom


03 进阶篇:HTTP协议——Web世界的“普通话”

你每天都在用的浏览器,其实就是个超级复杂的Socket客户端。只不过它遵循的是HTTP(超文本传输协议)

3.1 HTTP请求与响应结构

一个HTTP请求长什么样?我们可以把它拆解成四部分:

  1. 请求行GET /index.html HTTP/1.1

  2. 请求头Host: www.baidu.comUser-Agent: Chrome...

  3. 空行:分隔头信息。

  4. 请求体:POST请求中提交的表单数据或JSON。

服务器返回的响应也是类似的结构:

  1. 状态行HTTP/1.1 200 OK (200是成功,404是找不到,500是服务器错误)

  2. 响应头Content-Type: text/html...

  3. 空行

  4. 响应体:返回的HTML代码或JSON数据。

3.2 掌握“方法论”:常见的HTTP方法

很多同学只知道GET和POST,但HTTP的方法远不止这些:

  • GET:获取资源。数据在URL中,不安全,有长度限制。

  • POST:提交数据。数据在Body中,相对安全,适合提交表单。

  • PUT:更新资源(全量更新)。

  • DELETE:删除资源。

  • HEAD:只获取响应头,不获取Body。用于检测资源是否存在。


04 实战篇:从“调用者”变成“提供者”

光说不练假把式。我们来看看Python是如何通过requests库作为客户端调用API,再通过Starlette框架把自己变成一个Web服务器的。

4.1 案例一:发送HTTP请求(客户端)

requests库是Python中最优雅的HTTP客户端库。我们用它来调用“一言网”的API,获取一句随机名言。

python

import requests

url = 'https://v1.hitokoto.cn/'
params = {'c': 'a', 'encode': 'json'}

try:
    response = requests.get(url, params=params)
    if response.status_code == 200:
        data = response.json()
        print(f"名言:{data['hitokoto']} —— {data['from_who'] or '未知'}")
    else:
        print(f"请求失败,状态码:{response.status_code}")
except requests.RequestException as e:
    print(f"网络异常:{e}")

技术亮点requests.get 内部帮我们封装了复杂的Socket连接、TCP握手、HTTP报文拼装过程,让我们只需关注业务逻辑。

4.2 案例二:构建Web接口(服务端)

现在,我们把上面的功能封装成一个API,供别人调用。这里我们要请出两位大神:Uvicorn 和 Starlette

  • Uvicorn:ASGI服务器,异步、高性能,负责处理底层网络请求。

  • Starlette:轻量级Web框架,负责路由、请求处理。

python

from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
import requests
import uvicorn

HITOKOTO_URL = 'https://v1.hitokoto.cn/'

# 异步函数,模拟耗时操作
async def get_hitokoto():
    try:
        # 注意:requests是同步的,生产环境建议用httpx
        response = requests.get(HITOKOTO_URL, params={'c': 'a', 'encode': 'json'})
        data = response.json()
        return {'hitokoto': data['hitokoto'], 'from': data['from_who'] or '佚名'}
    except Exception as e:
        return {'error': str(e)}

# 路由处理函数
async def homepage(request):
    result = await get_hitokoto()  # 模拟异步调用
    return JSONResponse(result)

# 创建应用
app = Starlette(debug=True, routes=[Route('/', homepage)])

if __name__ == "__main__":
    uvicorn.run(app, host='0.0.0.0', port=8000)

运行效果
当你运行这段代码,你的电脑就成了一台Web服务器。打开浏览器访问 http://127.0.0.1:8000,就能看到随机返回的JSON数据。别人也可以通过这个地址来调用你的服务。

深度解析
这里使用了异步框架Starlette。虽然我们内部使用了同步的requests库,但通过async/await,我们向服务器声明了“当等待网络响应时,可以先去处理别的请求”。这在处理高并发时,能极大提升服务器的吞吐量。


05 总结:网络编程的“道”与“术”

从最底层的二进制数据,到应用层的JSON接口,我们梳理了整个技术链条。

  1. 理解分层思想:五层网络模型是理解网络编程的地图。遇到问题,先定位是哪一层的问题(是物理断网?还是DNS解析?还是代码逻辑?)。

  2. 掌握Socket精髓:无论你用多么高端的框架(如Django、FastAPI),底层都是Socket。搞懂recvsendbindlisten,你就能明白Web服务器是如何工作的。

  3. 区分TCP与UDP:这是面试高频题。记住,需要可靠就用TCP(文件、网页),需要速度就用UDP(直播、游戏)

  4. HTTP是应用层圣经:无论是爬虫还是写API,理解请求方法、状态码、消息结构是基本功。200不一定是成功(可能返回了错误JSON),500不一定全是代码bug(也可能是依赖服务挂了)。

最后,送给大家一句话:网络编程的本质,是让数据在不同的进程中优雅地穿梭。 掌握了今天的内容,你已经从“会用requests”的青铜,进化到了“理解网络本质”的铂金。接下来,不妨去深入看看asyncioFastAPI,去体验一下异步网络编程带来的性能跃迁。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐