I. struct
1. Brief introduction
We can use a module that converts the length of data to a fixed length of bytes. In this way, as long as the client accepts the fixed-length byte before receiving the message to see the size of the information to be received next, the final accepted data will stop as long as it reaches this value, and it will just receive a lot of complete data.
The module can convert a type, such as a number, into a fixed-length bytes
1 >>> struct.pack('i',1111111111111) 2 struct.error: 'i' format requires -2147483648 <= number <= 2147483647 #This is the scope.
1 import json,struct 2 #Suppose you upload 1 through the client T:1073741824000 Documents a.txt 3 4 #To avoid sticking,Must customize the header 5 header={'file_size':1073741824000,'file_name':'/a/b/c/d/e/a.txt','md5':'8f6fbf8347faa4924a76856701edb0f3'} #1T data,File paths and md5 value 6 7 #In order that the header can be transmitted,Need to be serialized and converted to bytes 8 head_bytes=bytes(json.dumps(header),encoding='utf-8') #Serialization and transformation bytes,Used for transmission 9 10 #To let the client know the length of the header,use struck Convert the header length number to a fixed length:4 Byte 11 head_len_bytes=struct.pack('i',len(head_bytes)) #These four bytes contain only one number.,This number is the length of the header. 12 13 #Client starts sending 14 conn.send(head_len_bytes) #Length of advance header,4 individual bytes 15 conn.send(head_bytes) #Byte format for retransmitting headers 16 conn.sendall(Document content) #Then send the real content in byte format 17 18 #Server begins to receive 19 head_len_bytes=s.recv(4) #Receive the first four newspapers bytes,Get the byte format of the header length 20 x=struct.unpack('i',head_len_bytes)[0] #Extract the length of the header and unpack it as a tuple 21 22 head_bytes=s.recv(x) #According to header length x,Receiving headlines bytes format 23 header=json.loads(json.dumps(header)) #Extract header 24 25 #Finally, real data is extracted from the content of the header.,such as 26 real_data_len=s.recv(header['file_size']) 27 s.recv(real_data_len)
2. Structurct Solves the Sticking Problem
With the help of the struct module, we know that the length number can be converted to a standard size of 4 bytes. Therefore, this feature can be used to pre-send data length.
Server
1 import socket 2 import subprocess 3 import struct 4 5 server = socket.socket() 6 ip_port = ('192.168.15.113',8001) 7 server.bind(ip_port) 8 server.listen() 9 conn,addr = server.accept() 10 while 1: 11 #Instructions from the client 12 print('Waiting for information...') 13 from_client_cmd = conn.recv(1024).decode('utf-8') 14 print(from_client_cmd) 15 #adopt subprocess Modules execute system instructions on the server side,And get the command execution results 16 sub_obj = subprocess.Popen( 17 from_client_cmd, #Client instructions 18 shell=True, 19 stdout=subprocess.PIPE, #standard output:The execution result of the correct instruction is here 20 stderr=subprocess.PIPE, #Standard error output:The execution result of the error instruction is here 21 ) 22 #The return information received is bytes Type, and windows The default code of the system is gbk 23 server_cmd_msg = sub_obj.stdout.read() 24 # server_cmd_err = sub_obj.stderr.read().decode('gbk') 25 #First calculate the length of the data you are sending. 26 cmd_msg_len = len(server_cmd_msg) 27 #Packing data length first,Data packaged into four bytes,The goal is to piece together the data you're sending.,Just so we customized a message header 28 msg_len_stru = struct.pack('i',cmd_msg_len) 29 conn.send(msg_len_stru) #First send the four bytes of data after successful packaging 30 conn.sendall(server_cmd_msg) #loop send data,Until all data is sent successfully
Client
1 import socket 2 import struct 3 client = socket.socket() 4 server_ip_port = ('192.168.15.113',8001) 5 client.connect(server_ip_port) 6 while 1: 7 msg = input('Please enter the instructions to be executed>>>') 8 client.send(msg.encode('utf-8')) 9 #The length of the message to be sent to me by the receiving server first,The first four bytes,Changeless 10 from_server_msglen = client.recv(4) 11 unpack_len_msg = struct.unpack('i',from_server_msglen)[0] 12 #Received data length statistics,Compare the length of data sent to me by the server,Determine the conditions for jumping out of the cycle 13 recv_msg_len = 0 14 #Statistical Stitching Received Data,Be careful:This is not statistical length. 15 all_msg = b'' 16 while recv_msg_len < unpack_len_msg: 17 every_recv_data = client.recv(1024) 18 #Stitching and counting the data received each time 19 all_msg += every_recv_data 20 #Accumulate the length of each received data 21 recv_msg_len += len(every_recv_data) 22 23 print(all_msg.decode('gbk'))
Complex server (custom header)
1 import socket,struct,json 2 import subprocess 3 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 4 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 5 6 phone.bind(('127.0.0.1',8080)) 7 phone.listen(5) 8 9 while True: 10 conn,addr=phone.accept() 11 while True: 12 cmd=conn.recv(1024) 13 if not cmd:break 14 print('cmd: %s' %cmd) 15 16 res=subprocess.Popen(cmd.decode('utf-8'), 17 shell=True, 18 stdout=subprocess.PIPE, 19 stderr=subprocess.PIPE) 20 err=res.stderr.read() 21 print(err) 22 if err: 23 back_msg=err 24 else: 25 back_msg=res.stdout.read() 26 27 headers={'data_size':len(back_msg)} 28 head_json=json.dumps(headers) 29 head_json_bytes=bytes(head_json,encoding='utf-8') 30 31 conn.send(struct.pack('i',len(head_json_bytes))) #Length of advance header 32 conn.send(head_json_bytes) #Recurrence header 33 conn.sendall(back_msg) #In the real content 34 35 conn.close() 36 37 tcp_server.py
1 from socket import * 2 import struct,json 3 4 ip_port=('127.0.0.1',8080) 5 client=socket(AF_INET,SOCK_STREAM) 6 client.connect(ip_port) 7 8 while True: 9 cmd=input('>>: ') 10 if not cmd:continue 11 client.send(bytes(cmd,encoding='utf-8')) 12 13 head=client.recv(4) 14 head_json_len=struct.unpack('i',head)[0] 15 head_json=json.loads(client.recv(head_json_len).decode('utf-8')) 16 data_len=head_json['data_size'] 17 18 recv_size=0 19 recv_data=b'' 20 while recv_size < data_len: 21 recv_data+=client.recv(1024) 22 recv_size+=len(recv_data) 23 24 #print(recv_data.decode('utf-8')) 25 print(recv_data.decode('gbk')) #windows default gbk Code 26 27 tcp_client.py
head = {'file name': 'test', 'filesize': 8192, 'filetype': 'txt', 'filepath': r'\user\bin'}
Header Len gt h --> Receive 4 bytes first
send(head) headers - > Get headers based on these four bytes
send(file) message - > Get filesize from the header, and then receive the file according to filesize
A general explanation of the whole process:
We can make headers into dictionaries, which contain descriptions of the real data to be sent (size, etc.), and then json serialization, and then use struck to package the serialized data length into four bytes.
All the data we transmit on the network is called data package. All the data in the data package is called message. There are not only your data in the message, but also your ip address, mac address, port number and so on. In fact, all messages have headers. This header is stipulated by the protocol. Look at it.
When sending:
Start-up header length
Re-encoding header content and sending
Final delivery of real content
When receiving:
First hand header length, take it out with struct
The header content is collected according to the length of the retrieved header, then decoded and deserialized.
Extract the descriptive information of the data to be retrieved from the result of deserialization, and then retrieve the real data content.