Python 网络编程入门:一文吃透 TCP Socket 通信
目录
前言
不管是聊天软件、网站服务、文件传输工具,底层全部依赖网络通信。作为 Python 开发者,Socket TCP 编程是后端、爬虫、服务开发的必备基础。
本文从底层网络原理讲起,结合编码转换、客户端 / 服务端实战、多并发服务、面试核心知识点(三次握手 / 四次挥手)完整梳理,零基础也能看懂。
一、计算机网络核心基础概念
1. 什么是计算机网络
将多台独立设备通过网线、路由器等设备连接,依靠网络协议实现资源共享、数据互传的平台,手机、电脑、服务器都属于网络设备
2. IP 地址
作用
IP 地址作为定位网络里唯一设备,是设备的网络 “身份证”,相当于手机号,用来在海量网络设备中精准找到目标机器
两种 IP 版本
IPv4(当前主流) 32 位二进制,点分十进制格式,例:
192.168.199.161,四段数字范围0~255,第一段限制1~223IPv6(下一代) 128 位地址,解决 IPv4 地址枯竭问题,自带加密、路由优化优势
查看本机 IP 命令
Windows:
ipconfigLinux/Mac:
ifconfig
网络连通测试:ping 命令
# 测试外网连通 ping www.baidu.com # 直接ping IP地址 ping 119.75.217.26无丢包、有返回时延代表网络正常
3. 端口号
端口号是定位设备上的软件程序
核心问题
一台电脑同时运行微信、QQ、浏览器,只有 IP 只能找到电脑,无法区分数据发给哪个软件,端口就是程序的专属通道
- IP:找到哪台电脑
- 端口号:找到电脑上哪个应用程序 举个例子:飞秋默认端口
2425,数据通过IP+端口精准送达对应软件
端口号分类(0~65535)
- 知名端口 0~1023:固定分配给标准服务
端口 服务 用途 21 FTP 文件传输 22 SSH 远程登录 80 HTTP 网页访问 443 HTTPS 加密网页
- 动态端口 1024~65535:程序自定义使用,我们开发 TCP 服务一般选用该区间
4. Socket 套接字
Socket 套接字是网络通信的工具
IP + 端口确定了通信双方,但需要工具完成收发数据,这个工具就是Socket,类比生活中的电话:
- 知道对方手机号(IP + 端口),必须有电话(Socket)才能通话。 所有网络软件底层都基于 Socket 实现,是程序之间网络交互的统一接口
5. TCP 协议
TCP 协议是一种可靠面向连接传输协议
TCP 两大核心特性
- 面向连接:通信前必须建立连接,通信结束断开连接,类似打电话,流程:建立连接→传输数据→关闭连接。
- 可靠传输,通过 4 种机制保证数据不丢、不乱序:
- 发送应答机制:发一条等对方确认再发下一条
- 超时重传:长时间无应答自动重发数据包
- 错误校验:校验数据完整性,损坏则重传
- 流量 / 拥塞控制:防止发送太快导致对方缓冲区溢出
对比 UDP(补充了解)
UDP 是无连接、不可靠协议,不用建立连接直接发数据,速度更快,但不保证数据送达,适合直播、游戏、语音等允许少量丢包场景
6.TCP 三次握手、四次挥手
三次握手(建立连接)
TCP 三次握手极简流程图
- 客户端发 SYN 报文:请求连接,进入
SYN-SENT- 服务端回 SYN+ACK:同意连接 + 确认客户端请求,进入
SYN-RCVD- 客户端回 ACK:确认服务端连接请求,双方进入
ESTABLISHED,连接就绪 作用:确认双方收发能力正常,避免无效连接四次挥手(断开连接)
TCP 四次挥手极简流程图
- 客户端发 FIN:我不再发数据,进入
FIN_WAIT_1- 服务端回 ACK:收到关闭请求,继续传输剩余数据,进入
CLOSE_WAIT- 服务端发 FIN:数据发完,请求关闭连接,进入
LAST_ACK- 客户端回 ACK:确认关闭,等待 2MSL 后彻底断开,服务端收到 ACK 直接关闭 作用:双方都传输完数据再断开,避免数据丢失
二、编码转换
计算机网络只能传输二进制 bytes 字节流,我们写的字符串无法直接发送,必须经过编码 / 解码。
核心方法
字符串.encode("utf-8"):编码,文本 → 二进制(发送数据使用)bytes.decode("utf-8"):解码,二进制 → 文本(接收数据使用)
示例代码
# 编码 msg = "你好,TCP网络编程" send_bytes = msg.encode("utf-8") print("编码后二进制:", send_bytes) # 解码 recv_str = send_bytes.decode("utf-8") print("解码后文本:", recv_str)注意:收发两端编码格式必须统一,否则会出现中文乱码(utf-8/GBK 二选一)
三、TCP 客户端开发
客户端开发五步走
- 创建 socket 套接字(socket)
- connect 连接服务端 IP + 端口
- send 编码后二进制数据
- recv 接收服务端响应并解码
- close 关闭套接字释放资源
完整客户端代码
import socket if __name__ == '__main__': # 1. 创建TCP套接字 AF_INET=IPv4 SOCK_STREAM=TCP tcp_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 2. 连接服务端(元组参数:(IP,端口)) tcp_client.connect(("127.0.0.1", 8080)) # 3. 发送数据,必须编码 send_msg = "服务端你好,我是客户端!" tcp_client.send(send_msg.encode("utf-8")) # 4. 接收响应,最大接收1024字节,解码 recv_data = tcp_client.recv(1024).decode("utf-8") print(f"收到服务端消息:{recv_data}") # 5. 关闭连接 tcp_client.close()
四、TCP 服务端开发
服务端七步走
客户端 & 服务端完整时序流程图
- 创建 socket 套接字
- bind 绑定本机 IP 和端口(必填,客户端靠端口找到服务)
- listen 开启监听,设置最大排队连接数
- accept 阻塞等待客户端连接,返回新通信套接字 + 客户端地址
- recv 接收客户端数据
- send 返回响应数据
- 关闭通信套接字、主监听套接字
版本 1:基础单客户端服务端
import socket if __name__ == '__main__': # 1. 创建套接字 tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 端口复用:解决重启服务端口被占用报错 tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) # 2. 绑定端口 ""代表本机所有网卡IP,127.0.0.1仅本地访问 tcp_server.bind(("", 8080)) # 3. 监听,最大排队128个连接 tcp_server.listen(128) print("服务端启动成功,等待客户端连接...") # 4. 阻塞等待客户端接入 conn_socket, client_addr = tcp_server.accept() print(f"新客户端接入:{client_addr}") # 5. 接收数据 recv_bytes = conn_socket.recv(1024) recv_msg = recv_bytes.decode("utf-8") print(f"客户端发来:{recv_msg}") # 6. 回复数据 resp = f"已收到你的消息:{recv_msg}" conn_socket.send(resp.encode("utf-8")) # 7. 关闭资源 conn_socket.close() tcp_server.close()
版本 2:面向对象封装服务端
import socket class TcpServer: def __init__(self, port=8080): # 初始化套接字 self.server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_sock.bind(("", port)) self.server_sock.listen(128) print(f"服务端启动,监听端口{port}") def handle_client(self, conn_sock, addr): """处理单个客户端消息""" recv_data = conn_sock.recv(1024).decode("utf-8") print(f"[{addr}] 客户端:{recv_data}") # 回复消息 conn_sock.send(f"服务端已读取:{recv_data}".encode("utf-8")) conn_sock.close() def start(self): # 循环持续接收客户端 while True: conn, addr = self.server_sock.accept() self.handle_client(conn, addr) if __name__ == '__main__': server = TcpServer(8080) server.start()
版本 3:多线程并发服务端
基础服务一次只能处理一个客户端,使用多线程实现并发:
import socket import threading # 单个客户端处理函数 def handle_conn(conn_sock, client_addr): while True: try: recv_bytes = conn_sock.recv(1024) # recv返回空代表客户端断开 if not recv_bytes: print(f"{client_addr} 客户端下线") break recv_msg = recv_bytes.decode("utf-8") print(f"[{client_addr}]:{recv_msg}") # 服务端主动发消息 send_msg = input("服务端回复:").encode("utf-8") conn_sock.send(send_msg) except ConnectionResetError: print(f"{client_addr} 异常断开") break conn_sock.close() if __name__ == '__main__': server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) server_sock.bind(("", 8080)) server_sock.listen(128) print("并发TCP服务启动,支持多客户端同时连接") while True: conn, addr = server_sock.accept() # 为每个客户端创建独立线程 client_thread = threading.Thread(target=handle_conn, args=(conn, addr)) client_thread.start()
五、TCP 网络编程必看注意事项
- 连接前提:客户端与服务端通信前必须建立 TCP 连接,无连接无法传输数据
- 端口绑定规则
- 客户端:无需手动绑定端口,操作系统自动分配临时端口
- 服务端:必须绑定固定端口,否则客户端找不到服务
- 两种套接字区分
listen()后的主套接字:只负责监听新连接,不能收发数据accept()返回的 conn 套接字:专门和单个客户端收发消息- 客户端下线判断:客户端调用
close()后,服务端recv()会返回空字节,可通过判断长度 0 识别客户端断开- 端口复用:添加
setsockopt代码,避免服务重启时提示端口被占用- 数据格式:所有收发数据必须是 bytes 二进制,字符串一定要 encode,接收后 decode
六、总结
- 网络通信三要素:IP(定位设备)+ 端口(定位程序)+Socket(通信工具)
- TCP 是面向连接、可靠传输协议,底层依靠三次握手建连、四次挥手断连
- 网络只传二进制,
encode编码发数据,decode解码读数据- 客户端五步、服务端七步是标准开发流程,多线程可实现并发多客户端
- 日常开发高频踩坑点:端口未绑定、编码不一致、忘记关闭套接字、端口占用
掌握这套基础后,HTTP 接口、文件传输、聊天室、爬虫底层通信逻辑都能轻松理解,是 Python 后端开发的核心基石
更多推荐







所有评论(0)