socket ---- python socket library
文章目录
英语名词
| words | explain |
|---|---|
| backlog | 积压的待办工作 |
| imperative | 必要的, 不可避免的 |
| it's imperative to do sth. | |
| switchboard | 配电盘 |
| switchboard operator | 总机,接线员(电话接线员) |
| overhead | 经常性的 |
| insideout | 心中有数(我自己认为的解释) |
| your app should be almost insideout. | |
| multiplex | 多路的,多工的 |
| simplex | 单一的,单工的 |
教程
https://realpython.com/python-sockets/#background 英文,易懂全面
https://docs.python.org/3/library/socketserver.html socketserver 模块
https://docs.python.org/3/library/socket.html 官方 socket 参考
https://docs.python.org/3/howto/sockets.html#socket-howto python 官方 socket 原理解说
linux 平台
man socket
- 关于 socket 的 C 语言接口说明
概念
mysocket.bind((host, port))
参数
host 取值
- "127.0.0.1", loopback, 只有本机能够连接
- "localhost", 同 127.0.0.1 效果一致
- 空串"",绑定到本机所有 ip 地址
port 取值
- 0, 保留值,不能使用
- 1~65535,可以使用
mysocket.socket()
参数
address family 地址
ip 协议
- ipv4, socket.AF_INET
- ipv6, socket.AF_INET6
- AF —> address family
- 本地通讯, socket.AF_UNIX, socket.AF_LOCAL
type
- 流类型
- socket.SOCK_STREAM
protocol
协议类型
- TCP
- UDP
mysocket.listen()
允许积压 backlog 连接申请数量
- 无参,使用默认值
Linux
- 系统允许的最多连接数量
通过文件配置
- /proc/sys/net/core/somaxconn
属性获取
socket.gethostname()
模块 socket 的函数,获取本机的 hostname
mysocket.getsockname()
返回值
- (ip, port)
传输数据
方式
- recv() 和 send()
write() 和 read()
实现方法
- 把 socket 转换城 file-like 对象
注意
- file-like 存在缓存 buffer 问题
- 写完数据,需要调用 flush()
- 不然对方,永远收不到
- 因为,数据还存在自己的 outpu buffer 中
mysocket.recv() 和 mysocket.send()
结束标志
- socket 本身并没有结束标志
单次使用的 socket
- 当对方调用了 close(), 已经不关闭或正在关闭
- 这时 recv(), 获取的是零个 byte,即(b'')
- 可以把它当作结束
实例
- http 协议,一般都是每一次传输创建一个 socket
重复使用
三种方法
- 消息定长
- 消息有确定的“结束标志”
关闭连接
- 消息处理方式
前缀法
在消息的前部,设置类型或长度标志
缺点
- 对方原样返回,会造成错误
mysocket.sendall()
- 一次性传输所有数据
- 不同于 mysocket.send(): 单次只能传输一定数据,循环调用
mysocket.close() 关闭与 disconnecting
shutdown()
- 位置:应当在 close()前调用 shutdown()
- 作用:表明发送数据 send()结束,但是 recv()还在进行
确保关闭
- 需要调用 close()函数
可以使用 with
1 2with socket.socket() as s: pass使用 try, finnaly
1 2 3 4 5try: conn, addr = server.accept() conn.recv(10) finally: conn.close()
异常中断
工具
返回值判断
- mysocket.send() == 0
mysocket.recv() == 0
1 2 3 4 5 6 7 8 9 10def myreceive(self): chunks = [] bytes_recd = 0 while bytes_recd < MSGLEN: chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048)) if chunk == b'': raise RuntimeError("socket connection broken") chunks.append(chunk) bytes_recd = bytes_recd + len(chunk) return b''.join(chunks)
原因
- 另一方在未调用 close()之前断开连接
处理
- 如果是线程,可以不必杀掉线程
非阻塞型 socket Non-Blocking Socket
https://docs.python.org/3/howto/sockets.html#non-blocking-sockets
方法
socket.setblocking(0)
- 程序可能会很复杂
使用 select 模块
- select 有一个对应的高级模块 slectors
makefile() 转换 file-like object
mysocket.makefile()
获取未被占用端口
- 申请端口
- 设置端口可重用 sock.SO_REUSEADDR
- 提取端口号
- 关闭 socket
| |
文章作者
上次更新 2022-03-03 (5c64003)