2. Packet sticking (struct module) and struct module
The socket we made yesterday has a vulnerability, and it will be stuck to the package. We will present it today if we have not found this problem. Today, we will also explain a little about udp-based sockets.
1. udp-based socket
There is no link to udp. No error will be reported when udp is started first.
Udp Server:
Ss = socket () # create a server socket ss. bind () # bind a server socket while True: # server infinite loop cs = ss. recvfrom ()/ss. sendto () # receive and send a dialog ss. close () # close the server socket
Udp client:
Cs = socket () # create a customer socket while True: # communication loop cs. sendto ()/cs. recvfrom () # Send/receive cs. close () # close customer socket
1. simple udp socket instance
Server:
from socket import *udp_ss=socket(AF_INET,SOCK_DGRAM)udp_ss.bind(('127.0.0.1',8080))while True: msg,addr=udp_ss.recvfrom(1024) print(msg,addr) udp_ss.sendto(msg.upper(),addr)
Client:
from socket import *udp_cs=socket(AF_INET,SOCK_DGRAM)while True: msg=input('>>: ').strip() if not msg:continue udp_cs.sendto(msg.encode('utf-8'),('127.0.0.1',8080)) msg,addr=udp_cs.recvfrom(1024) print(msg.decode('utf-8'),addr)
2. simulate a chat (Because udp is not connected, multiple clients can communicate with the server at the same time)
Server:
From socket import * udp_ss = socket (AF_INET, SOCK_DGRAM) udp_ss.bind ('2017. 0.0.1 ', 8081) while True: msg, addr = udp_ss.recvfrom (1024) print ('message from [% s]: % s' % (addr, msg. decode ('utf-8') msg_ B = input ('reply message :'). strip () udp_ss.sendto (msg_ B .encode ('utf-8'), addr)
Client 1:
From socket import * udp_cs = socket (AF_INET, SOCK_DGRAM) while True: msg = input ('Enter the message and press enter to send :'). strip () if msg = 'quit': break if not msg: continue udp_cs.sendto (msg. encode ('utf-8'), ('2017. 0.0.1 ', 8081) back_msg, addr = udp_cs.recvfrom (1024) print ('message from [% s]: % s' % (addr, back_msg.decode ('utf-8') udp_cs.close ()
Client 2:
From socket import * udp_cs = socket (AF_INET, SOCK_DGRAM) while True: msg = input ('Enter the message and press enter to send :'). strip () if msg = 'quit': break if not msg: continue udp_cs.sendto (msg. encode ('utf-8'), ('2017. 0.0.1 ', 8081) back_msg, addr = udp_cs.recvfrom (1024) print ('message from [% s]: % s' % (addr, back_msg.decode ('utf-8') udp_cs.close ()
Client 3:
......
Because different clients send messages to the same server, the client code is the same. If you are interested, you can use several computers for testing (the computer needs to be connected to the Internet)
Ii. Package sticking
First stick the package:
Server:
from socket import *phone=socket(AF_INET,SOCK_STREAM)phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)phone.bind(('127.0.0.1',8080))phone.listen(5)conn,client_addr=phone.accept()data1=conn.recv(1024)print('data1: ',data1)data2=conn.recv(1024)print('data2:',data2)
Client:
from socket import *phone=socket(AF_INET,SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('hello'.encode('utf-8'))phone.send('world'.encode('utf-8'))
Let's take out the ssh example in the previous article (execute ipconfig/all and then execute dir to view the result)
Client:
From socket import * import subprocesscs = socket (AF_INET, SOCK_STREAM) cs. setsockopt (SOL_SOCKET, SO_REUSEADDR, 1) cs. bind ('2017. 0.0.1 ', 8082) cs. listen (5) print ('starting... ') while True: conn, addr = cs. accept () print ('-------->', conn, addr) while True: try: cmd = conn. recv (1024) res = subprocess. popen (cmd. decode ('utf-8'), shell = True, stdout = subprocess. PIPE, stderr = subprocess. PIPE) stdout = res. stdout. read () stderr = res. stderr. read () # send command result conn. send (stdout + stderr) failed t Exception: break conn. close () # Call cs. close () # shut down
Server:
From socket import * ss = socket (AF_INET, SOCK_STREAM) # Buy Mobile Phone ss. connect ('2017. 0.0.1 ', 8082) # bind the mobile phone card # send and receive the message while True: cmd = input (' >> :'). strip () if not cmd: continue ss. send (cmd. encode ('utf-8') has _res = ss. recv (1024) print (pai_res.decode ('gbk') ss. close ()
Note:
The encoding of the result of the subprocess module is based on the current system. For windows, res. stdout. read () reads GBK encoding, and GBK decoding is required at the receiving end.
3. Stick the package
Note: UDP never sticks to packets only when TCP is used. First, you must understand the principle of sending and receiving messages through a socket.
The data seen by an application is a whole, or a stream. The number of bytes of a message is invisible to the application. Therefore, TCP is a stream-oriented protocol, this is also the cause of the sticking problem.
For example, when a tcp-based Socket Client uploads a file to the server, the file content is sent according to the byte stream of a segment, I don't know where the object's byte stream starts or ends.
The so-called packet sticking problem is mainly because the receiver does not know the boundaries between messages and how many bytes of data are extracted at a time.
In addition, the adhesive packet caused by the sender is caused by the TCP protocol itself. To improve transmission efficiency, the sender often needs to collect enough data before sending a TCP segment. If few data needs to be sent several times in a row, TCP will usually combine the data into a TCP segment and send it once Based on the optimization algorithm, so that the receiver receives the sticky packet data.
In either case, the package will be stuck:
1. The sender needs to wait until the buffer zone is full before sending it out, resulting in a sticky packet (the data sending interval is very short, the data is very small, and the packets are merged to generate a sticky packet)
2. the receiver does not receive packets in the buffer in time, resulting in receiving multiple packets (the client sends a small portion of data, and the server only receives a small portion of the data, the server will take the data left over from the buffer zone next time to generate a sticky package)
Occurrence of unpacking:
When the buffer length at the sending end is greater than the MTU of the NIC, tcp splits the sent data into several packets for sending.
Iv. Solution to sticking packets
Solve the first problem of sticking packets:
Solution 1: (you need to know the amount of data sent each time is unrealistic)
from socket import *phone=socket(AF_INET,SOCK_STREAM)phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)phone.bind(('127.0.0.1',8080))phone.listen(5)conn,client_addr=phone.accept()data1=conn.recv(10)print('data1: ',data1)data2=conn.recv(4)print('data2:',data2)
Server
from socket import *phone=socket(AF_INET,SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('helloworld'.encode('utf-8'))phone.send('egon'.encode('utf-8'))
Client
Solution 2:
from socket import *phone=socket(AF_INET,SOCK_STREAM)phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)phone.bind(('127.0.0.1',8080))phone.listen(5)conn,client_addr=phone.accept()data1=conn.recv(1024)print('data1: ',data1)data2=conn.recv(1024)print('data2:',data2)
Server
from socket import *import timephone=socket(AF_INET,SOCK_STREAM)phone.connect(('127.0.0.1',8080))phone.send('hello'.encode('utf-8'))time.sleep(5)phone.send('world'.encode('utf-8'))
Client
Solve the problem with the ssh example:
Add a custom fixed-length header to the byte stream. The header contains the byte stream length, which is then sent to the peer end at one time. When the peer end receives the header, it first extracts the fixed-length header from the cache, and then extract the real data.
From socket import * import subprocessimport structss = socket (AF_INET, SOCK_STREAM) ss. bind ('2017. 0.0.1 ', 8082) ss. listen (5) print ('starting... ') while True: conn, addr = ss. accept () print ('-------->', conn, addr) while True: try: cmd = conn. recv (1024) res = subprocess. popen (cmd. decode ('utf-8'), shell = True, stdout = subprocess. PIPE, stderr = subprocess. PIPE) stdout = res. stdout. read () stderr = res. stderr. read () # Forward header (converted to bytes type of Fixed Length) header = struct. pack ('I', len (stdout) + len (stderr) conn. send (header) # resend the command result conn. send (stdout) conn. send (stderr) failed t Exception: break conn. close () ss. close ()
Server
From socket import * import structcs = socket (AF_INET, SOCK_STREAM) cs. connect ('2017. 0.0.1 ', 8082) while True: cmd = input ('>> :'). strip () if not cmd: continue cs. send (cmd. encode ('utf-8') # first accept header header_struct = cs. recv (4) unpack_res = struct. unpack ('I', header_struct) total_size = unpack_res [0] # recollect data recv_size = 0 #10241 = 10240 + 1 total_data = B ''while recv_size <total_size: recv_data = cs. recv (1024) recv_size + = len (recv_data) total_data + = recv_data print (total_data.decode ('gbk') cs. close ()
Client
5. struct module (understanding)
This module can convert a type, such as a number, to a bytes with a fixed length.
Struct. pack ('I', 11111111) # struct. error: 'I' format requires-2147483648 <= number <= 2147483647 # This is the range
Struct. pack is used to convert Python values to strings Based on format characters (because Python does not have a Byte type ). Its function is prototype: struct. unpack (fmt, string ).
Struct. unpack is the opposite of struct. pack. It is used to replace byte Transfer with python data type. Its function is prototype: struct. unpack (fmt, string). This function returnsTuples.