send和recv
一个send可以对应多个recv
# 服务端: import socket server = socket.socket() server.bind(('127.0.0.1',9045)) server.listen(5) conn,addr = server.accept() print(conn.recv(10)) print(conn.recv(10)) print(conn.recv(10)) print(conn.recv(10)) print(conn.recv(10)) print(conn.recv(10)) #在数据取完了之后再recv的数据是空 conn.close() server.close() # 客户端: import socket client = socket.socket() client.connect(('127.0.0.1',9045)) client.send(b'sfaugsdaifjaskdbvziwadF') client.close() # 结果: b'sfaugsdaif' b'jaskdbvziw' b'adF' b'' b'' b''
一个recv可以对应多个send
# 服务端: import socket server = socket.socket() server.bind(('127.0.0.1',9045)) server.listen(5) conn,addr = server.accept() print(conn.recv(1024)) # send多次发送少量数据,一次打印出来 conn.close() server.close() # 客户端: import socket client = socket.socket() client.connect(('127.0.0.1',9045)) client.send(b'sfa') client.send(b'as') client.send(b'iwa') client.send(b'tf') client.close() # 结果: b'sfaasiwatf'
总结:
1.send和recv不是必须要一一对应的
2.只要通道不关闭的状态下,而且客户端不给服务端发数据,服务端就会一直处于recv状态
粘包问题解决
low版
# 服务端: import socket import subprocess import struct server = socket.socket() server.bind(('127.0.0.1',8848)) server.listen(5) while 1: conn,addr = server.accept() while 1: try: cmd = conn.recv(1024).decode('utf-8') obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) right_msg = obj.stdout.read() error_msg = obj.stderr.read() # 获取数据总长度 total_data_size = len(right_msg + error_msg) print(total_data_size) # 将总长度转化成固定长度的字节 total_data_size_bytes = struct.pack('i',total_data_size) #无论总长度是几位,转化后长度都是4 # 发送总长度字节和总数据 conn.send(total_data_size_bytes) conn.send(right_msg + error_msg) except Exception: break conn.close() server.close() # 客户端: import socket import struct client = socket.socket() client.connect(('127.0.0.1',8848)) while 1: cmd = input('>>>').strip() client.send(cmd.encode('utf-8')) # 接收固定长度 head_bytes = client.recv(4) # 将head_bytes还原成int类型 total_data_len = struct.unpack('i',head_bytes)[0] # unpack转化之后是元祖的形式,用下标将int取出来 print('长度:',total_data_len) # 循环接收所有的数据 total_data = b'' while len(total_data) < total_data_len: data = client.recv(1024) total_data += data print(total_data.decode('gbk')) client.close()
缺点:
1.数据如果过大,struct就会报错
2.如果上传下载文件(视频,音频,文件等),需要自定义报头(文件名,路径,大小,md5值等)
高端版
# 服务端: import socket import subprocess import struct import json server = socket.socket() server.bind(('127.0.0.1',8888)) server.listen(5) while 1: conn, addr = server.accept() while 1: try: cmd = conn.recv(1024).decode('utf-8') obj = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) right_msg = obj.stdout.read() error_msg = obj.stderr.read() # 1, 自定制报头 head_dic = { 'file_name': 'xx.mp4', 'file_path': r'C:UsersoldboyPycharmProjectss19day30 4 recv的问题server.py', 'file_size': len(error_msg + right_msg), } # 2,将head_dic利用json转化成json字符串 head_dic_json = json.dumps(head_dic) # 3,将json字符串转化成bytes head_dic_json_bytes = head_dic_json.encode('utf-8') # 4,利用strcut将head_dic_json_bytes转化成固定的4个字节 head_dic_json_bytes_struct = struct.pack('i',len(head_dic_json_bytes)) # 内容bytes长度固定的4个字节 # print(head_dic_json_bytes_struct,len(head_dic_json_bytes_struct)) # 5,发送固定4个字节 conn.send(head_dic_json_bytes_struct) # 6,发送bytes类型的字典的报头数据head_dic_json_bytes conn.send(head_dic_json_bytes) # 7, 发送总数据 conn.send(right_msg + error_msg) except Exception: break conn.close() server.close() # 客户端: import socket import struct import json client = socket.socket() client.connect(('127.0.0.1',8888)) while 1 : cmd = input('>>>').strip() client.send(cmd.encode('utf-8')) # 1,接受4个字节 head_dic_json_bytes_size_strcut = client.recv(4) # 2,利用struct反解出head_dic_json_bytes的具体size head_dic_json_bytes_size = struct.unpack('i',head_dic_json_bytes_size_strcut)[0] # 3,接受head_dic_json_bytes具体数据 head_dic_json_bytes = client.recv(head_dic_json_bytes_size) # 4,将head_dic_json_bytes转化成json的格式 head_dic_json = head_dic_json_bytes.decode('utf-8') # 5, head_dic_json 反序列化成字典类型 head_dic = json.loads(head_dic_json) # 6 循环接收数据 total_data = b'' while len(total_data) < head_dic['file_size']: total_data += client.recv(1024) print(total_data.decode('gbk')) client.close()