必须显式指定AF_INET和SOCK_STREAM,因为socket()不接受默认参数,AF_INET标识IPv4地址族,SOCK_STREAM对应TCP协议,二者共同定义面向连接、可靠传输的通信行为。

为什么socket.socket()要指定AF_INET和SOCK_STREAM?
不指定地址族和套接字类型,socket()会抛出TypeError: socket() takes at least 1 argument (0 given)。Python 的 socket 模块要求显式声明协议栈和传输层行为:AF_INET 表示 IPv4 地址(不是 AF_INET6),SOCK_STREAM 对应 TCP(可靠、有序、面向连接),而 SOCK_DGRAM 对应 UDP(无连接、不可靠、报文边界保留)。
常见误写是漏掉 AF_INET 或错用 AF_UNIX(仅限本地 IPC),导致 AddressFamily not supported 错误。Windows 和 Linux 下都必须严格匹配。
-
AF_INET+SOCK_STREAM→ TCP 客户端/服务器 -
AF_INET+SOCK_DGRAM→ UDP 客户端/服务器 - 不要混用:比如用
SOCK_STREAM调sendto()会报OSError: [WinError 10057](Windows)或Socket operation on non-socket(Linux)
TCP 服务器为何必须调用bind()后再listen()?
bind() 把 socket 绑定到具体 IP 和端口,否则系统不知道该监听哪张网卡、哪个端口;listen() 才真正启用连接队列。跳过 bind() 直接 listen() 会触发 OSError: [Errno 10049] The requested address is not valid in its context(Windows)或 socket.error: [Errno 99] Cannot assign requested address(Linux)。
典型写法:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('127.0.0.1', 8080)) # 必须先 bind
sock.listen(5) # 再 listen,参数是 backlog 长度- 绑定
'0.0.0.0'表示监听所有本地 IPv4 接口,但需注意防火墙和权限(如非 root 进程不能绑定 1–1023 端口) -
listen(5)中的 5 是已完成三次握手但尚未被accept()取走的连接数上限,不是并发连接总数 - 若端口已被占用,
bind()报Address already in use,加sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)可避免 TIME_WAIT 占用问题
UDP 收发数据为什么不用connect()也能用send()?
UDP 是无连接协议,send() 会失败并提示 OSError: [Errno 10049] The requested address is not valid in its context,因为未指定目标地址——它只适用于已调用 connect() 的 UDP socket(此时可像 TCP 一样用 send() 和 recv())。正常 UDP 发送必须用 sendto() 并传入地址元组,接收用 recvfrom() 获取数据和来源地址。
-
sock.sendto(b'hello', ('127.0.0.1', 8080))→ 正确 -
sock.send(b'hello')→ 报错,除非先sock.connect(('127.0.0.1', 8080)) -
recvfrom(1024)返回(data, (host, port)),比recv()多一个地址信息,这对服务端识别不同客户端至关重要 - UDP 不保证送达,也不保证顺序,
recvfrom()可能阻塞,超时需设sock.settimeout(3)
为什么recv()有时只收到部分数据?
TCP 是字节流协议,recv(n) 最多返回 n 字节,但可能少于 n(比如网络中断、对端发得少、内核缓冲区暂未填满)。这不表示错误,而是 TCP 的正常行为。常见现象是发送 b'{"msg":"ok"}\n',但 recv(1024) 只读到 b'{"msg":',下一次才读到剩余内容。
- 永远不要假设单次
recv()能拿到完整应用层消息 - 解决办法:自己拼接缓冲区,按分隔符(如
\n)或长度前缀(如前 4 字节为 int 表示 body 长度)解析 - UDP 的
recvfrom()不会出现“半包”,因为每个sendto()对应一个独立报文,但要注意 MTU 限制(通常 ≤1500 字节),超长会被静默截断 - 使用
socket.MSG_WAITALL标志可让recv()尽量等待满 n 字节,但仍有超时或连接关闭风险,不推荐用于生产环境
实际写通信逻辑时,最易被忽略的是 TCP 的流特性与应用层消息边界的脱节——这不是 bug,是协议设计使然。处理不当就会出现粘包或拆包,后续调试成本远高于一开始就做缓冲管理。

















