自定制报头
1.recv的工作原理
源码解释:
Receive up to buffersize bytes from the socket.
接收来自socket缓冲区的字节数据,
For the optional flags argument, see the Unix manual.
对于这些设置的参数,可以查看Unix手册。
When no data is available, block untilat least one byte is available or until the remote end is closed.
当缓冲区没有数据可取时,recv会一直处于阻塞状态,直到缓冲区至少有一个字节数据可取,或者远程端关闭。
When the remote end is closed and all data is read, return the empty string.
关闭远程端并读取所有数据后,返回空字符串。
2.高大上版解决粘包方式(自定义报头)
# server服务端
import socket
import struct
import json
import subprocess
phone = socket.socket()
phone.bind(("127.0.0.1", 8848))
phone.listen()
while 1:
conn, addr = phone.accept()
print(conn, addr)
while 1:
try:
from_client_data = conn.recv(1024)
# print(f"{from_client_data.strip().decode('utf-8')}")
obj = subprocess.Popen(from_client_data.decode("utf-8"),
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
to_client_data = obj.stdout.read() + obj.stderr.read()
total_size = len(to_client_data)
head_dic = {"file_name": "test", "md5": 646846, "total_size": total_size}
# 报头字典
head_dic_json_bytes = json.dumps(head_dic).encode("utf-8")
# 报头字典str然后转字节
len_head_dic_json_bytes = len(head_dic_json_bytes)
# 报头字典str字节数
four_head_bytes = struct.pack("i", len_head_dic_json_bytes)
# 制作报头字典字节int的固定字节数
conn.send(four_head_bytes)
# 发送报头字典字节int的固定字节数
conn.send(head_dic_json_bytes)
# 发送报头字典
conn.send(to_client_data)
# 发送总数据
except ConnectionResetError:
print("客户端中断")
break
conn.close()
phone.close()
# client客户端
import socket
import struct
import json
phone = socket.socket()
phone.connect(("127.0.0.1", 8848))
while 1:
to_server_data = input(">>>").strip().encode("utf-8")
if not to_server_data:
print("输出不能为空")
phone.send(to_server_data)
if to_server_data.upper() == b'Q':
print("客户端退出")
four_head_bytes = phone.recv(4)
# 接收报头字典的固定字节
len_head_dic_json_bytes = struct.unpack("i", four_head_bytes)[0]
# 报头字典的字节数
head_dic_json_bytes = phone.recv(len_head_dic_json_bytes)
# 接收报头字典字节
head_dic = json.loads(head_dic_json_bytes.decode("utf-8"))
# 报头字典
recv_size = 0
from_server_data = b''
while recv_size < head_dic["total_size"]:
recv_data = phone.recv(1024)
from_server_data += recv_data
recv_size += len(recv_data)
print(from_server_data.decode("gbk"))
3.基于UDP协议的socket通信
先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),recvform接收消息,这个消息有两项,消息内容和对方客户端的地址,然后回复消息时也要带着你收到的这个客户端的地址,发送回去,最后关闭连接,一次交互结束
发消息必须带着自己的地址,这就是UDP不一样的地方,不需要建立连接,但是要带着自己的地址给服务端,否则服务端无法判断是谁给我发的消息,并且不知道该把消息回复到什么地方,因为我们之间没有建立连接通道
# server端
import socket
while 1:
phone = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
phone.bind(("127.0.0.1", 8848))
from_msg, addr = phone.recvfrom(1024)
print(from_msg.decode("utf-8"), addr)
to_msg = input(">>>").strip().encode("utf-8")
phone.sendto(to_msg, addr)
phone.close()
# client端
import socket
phone = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_client = ("127.0.0.1", 8848)
while 1:
to_msg = input(">>>").strip().encode("utf-8")
phone.sendto(to_msg, ip_client)
if to_msg.upper() == b'Q' :
print("退出成功")
break
from_msg, addr = phone.recvfrom(1024)
print(from_msg.decode("utf-8"), addr)
phone.close()