socket
1, 定义
套接字
基于 tcp 协议
socket 是基于应用层与传输层之间的抽象层, 是一组操作起来非常简单的接口, 接收应用层的数据, 然后传给操作系统
分类:
基于文件类型的套接字家族: AF-UNIX, 不常用
基于网络类型的套接字家族: AF-.NET
模块语法
shell: 命令解释器, 相当于调用 cmd, 执行指定的命令
stdout: 正确结果以字符串的形式 send 个客户端
stderr: 错误的结果以字符串的形式 send 给客户端
Windows 操作系统的默认编码是 gbk
粘包
粘包的两种方式
连续短暂的多次 send, 数据量很小, 数据就会统一发出去
send 的数据过大, 大于对方 recv 的上限时, 对方第一次 recv 时, 会接收上一次没有 recv 完的剩余数据, 这就是粘包
只有 tcp 会粘包, udp 永远不会粘包, 粘包现象的发生于缓冲区有关系
缓存区
暂时储存一些数据
缓存取得存在, 避免了网络波动等影响对数据传输的影响, 保证了数据的收发稳定, 匀速
缺点: 就是照成了粘包现象
解决粘包现象
发送数据长度, 客服端循环接收数据知道接收完数据
自定义报头
ftp 协议
1, 文件传输协议
FTP 使用两个并行的 TCP 连接来传输文件, 一个是控制连接(用于在两主机之间传递控制信息), 一个是数据连接(用于实际传输一个文件). 因为 FTP 协议使用一个分离的控制连接, 所以我们也称 FTP 的控制信息是带外传送的
自定制报头
可以解觉文件过大的问题
2, 服务端要点
自定义报头
- head_dic = {"filename":"文件名",
- "md5":11111111111,
- "size":total_size}
JSON 形式的报头
head_dic_json = JSON.dumps(head_dic)
bytes 形式报头
head_dic_json_bytes = head_dic_json.encoude('utf-8')
bytes 长度
len_head = len(head_dic_json_bytes)
将不固定的 int 总字节数转换成固定长度的 4 个字节
head_size = struct.pack('i',len_head)
发送固定字节
conn.send(head_size)
发送字典的 bytes 数据
conn.send(head_dic_json_size)
发送总数据(result)
3, 客户端要点
接收 4 个固定字节的报头
from_server_data = client.recv(4)
将接收到的 4 个字节的固定报头翻转会字典的 bytes 长度
len_dic_size = struct.unpack('i',from_server_data)
通过翻转的长度接收字典的 bytes 数据
dic_bytes = client.recv(len_dic_size)
将 bytes 类型装换成 JSON 类型的字典
dic_json = dic_bytes.decode('utf-8')
JSON 反序列化成原字典
dic = JSON.loads(dic_json)
得到原字典就得到了源数据的总字节数
- total_size = dic["size"]
- udp
服务端
基于 udp 协议的 socket 无序建立管道, 先开启服务端或者客户端都行
基于 udp 协议的 socket 接收一个消息, 与发送一个消息都是无连接的
只要拿到我都 IP 地址和端口就可以给我发消息, 我按照顺序接收消息
- import socket
- server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- # 基于网络的 UDP 协议的 socket
- server.bind(('192.168.14.198',9000))
- while 1:
- from_client_data = server.recvfrom(1024) # 阻塞, 等待客户来消息
- print(f'\033[1;35;0m 来自客户端{from_client_data[1]}: {from_client_data[0].decode("utf-8")} \033[0m')
- # to_client_data = input('>>>').strip()
- # server.sendto(to_client_data.encode('utf-8'),from_client_data[1])
2,client 端
- ? udp
- import socket
- client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
- # 基于网络的 UDP 协议的 socket
- while 1:
- to_server_data = input('>>>:').strip()
- client.sendto(to_server_data.encode('utf-8'),('127.0.0.1',9000))
- # data,addr = client.recvfrom(1024)
- # print(f'来自服务端 {addr} 消息:{data.decode("utf-8")}')
来源: http://www.bubuko.com/infodetail-3329356.html