31_Network Programming-Strct

Keywords: Python socket JSON encoding shell

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.

Posted by bigfunkychief on Sat, 19 Jan 2019 05:12:12 -0800