前言
网络编程是后端开发、爬虫、即时通讯等场景的基础,而socket就是实现网络通信最核心的接口。很多初学者刚接触网络编程时,会被tcp、udp、ip、端口等概念搞得一头雾水。本篇从基础概念出发,使用原生python标准库socket,从零搭建服务端与客户端通信示例,带你快速上手socket编程。
前置要求:掌握python基础语法,无需深入网络底层原理。python内置socket模块,不需要额外pip安装。
一、什么是socket
socket(套接字)可以理解为网络上两个程序通信的端点。
两台主机想要互相传递数据,一端开启服务监听,另一端发起连接,依靠ip地址+端口唯一标识一个socket通信通道。
两种最常用通信协议:
- tcp:面向连接、可靠通信,数据不会丢失、顺序不变。通信前必须建立连接(三次握手),文件传输、聊天软件大多使用tcp。
- udp:无连接、不可靠通信,不用建立连接,发送速度快,适合直播、语音通话、广播场景,可能丢包。
python socket库同时支持tcp与udp套接字。
二、tcp通信完整示例(重点)
tcp通信流程:
- 服务端:创建socket → 绑定ip端口(bind) → 开始监听(listen) → 阻塞等待连接(accept) → 收发数据
- 客户端:创建socket → 连接服务端(connect) → 收发数据
2.1 tcp服务端代码 server.py
import socket
# 1. 创建tcp套接字 sock_stream代表tcp
server_socket = socket.socket(socket.af_inet, socket.sock_stream)
# 2. 绑定地址与端口,0.0.0.0代表监听本机所有网卡
host = "0.0.0.0"
port = 8888
server_socket.bind((host, port))
# 3. 开启监听,参数为允许等待的最大连接数
server_socket.listen(5)
print(f"服务端启动成功,监听端口:{port}")
# 4. 循环等待客户端接入
while true:
# accept()阻塞,直到有客户端连接
conn, addr = server_socket.accept()
print(f"新客户端接入:{addr}")
# 接收客户端数据,缓冲区大小1024字节
data = conn.recv(1024)
if not data:
conn.close()
continue
print("收到客户端消息:", data.decode("utf-8"))
# 向客户端发送响应
resp = "服务端已收到你的消息!"
conn.send(resp.encode("utf-8"))
# 关闭当前客户端连接
conn.close()
2.2 tcp客户端代码 client.py
import socket
# 创建tcp套接字
client_socket = socket.socket(socket.af_inet, socket.sock_stream)
# 连接服务端地址
host = "127.0.0.1"
port = 8888
client_socket.connect((host, port))
# 发送数据,socket只能传输字节流,字符串需要encode编码
msg = "hello socket!"
client_socket.send(msg.encode("utf-8"))
# 接收服务端返回消息
recv_data = client_socket.recv(1024)
print("收到服务端响应:", recv_data.decode("utf-8"))
# 关闭套接字
client_socket.close()
运行测试
- 终端先运行服务端:
python server.py - 新开终端运行客户端:
python client.py
输出效果:
服务端控制台:
服务端启动成功,监听端口:8888
新客户端接入:('127.0.0.1', 51234)
收到客户端消息: hello socket!
客户端控制台:
收到服务端响应: 服务端已收到你的消息!
注意要点:
- socket传输只有bytes字节流,字符串必须
encode(),接收后使用decode()解码; 127.0.0.1仅本机访问;想要局域网其他设备连接,服务端绑定0.0.0.0,客户端填写服务端局域网ip;- 端口不能被其他程序占用,占用会抛出
oserror。
三、udp通信示例
udp不需要建立连接,不需要listen和accept,收发更加轻量化。
udp服务端 udp_server.py
import socket
# sock_dgram 代表udp
udp_server = socket.socket(socket.af_inet, socket.sock_dgram)
udp_server.bind(("0.0.0.0", 9999))
print("udp服务端启动,端口9999")
while true:
data, addr = udp_server.recvfrom(1024)
print(f"来自{addr}消息:{data.decode('utf-8')}")
udp_server.sendto("udp收到!".encode("utf-8"), addr)
udp客户端 udp_client.py
import socket
udp_client = socket.socket(socket.af_inet, socket.sock_dgram)
udp_client.sendto("udp测试消息".encode("utf-8"), ("127.0.0.1", 9999))
data, addr = udp_client.recvfrom(1024)
print("服务端回复:", data.decode("utf-8"))
udp_client.close()
四、常见踩坑总结
- 编码报错:收发忘记encode/decode,中文极易出现乱码,统一使用utf-8;
- 端口占用:修改port,或者关闭占用端口的进程;
- 客户端连不上:防火墙拦截、ip填写错误、服务端未绑定
0.0.0.0; - recv阻塞卡死:tcp连接断开后recv会返回空字节,代码中需要判断;
- 单次recv不能接收全部大数据:缓冲区有限,传输大文件需要循环接收。
五、进阶拓展方向
原生基础socket仅实现一对一短连接通信,后续可以延伸学习:
- 使用多线程/多进程处理多个客户端并发连接;
- io多路复用 select / selectors 实现高并发服务;
- 基于socket实现简易聊天室、文件传输;
- 封装协议头,自定义通信数据包格式;
- 异步网络编程 asyncio socket;
- 第三方框架:twisted、gevent。
结束语
socket是网络编程的基石,http、websocket底层依然基于socket封装。熟练掌握原生socket模块,能帮助你理解各类网络框架底层通信逻辑。本篇示例均为最简可运行代码,建议手动敲一遍运行调试,加深理解。
到此这篇关于python使用socket模块实现网络编程的入门指南的文章就介绍到这了,更多相关python socket网络编程内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论