一 TCP sockets
As you’ll see shortly, we’ll create a socket object using socket.socket() and specify the socket type as socket.SOCK_STREAM. When you do that, the default protocol that’s used is the Transmission Control Protocol (TCP). This is a good default and probably what you want.
-
Is reliable: packets dropped in the network are detected and retransmitted by the sender.
-
Has in-order data delivery: data is read by your application in the order it was written by the sender.
In contrast, User Datagram Protocol (UDP) sockets created with socket.SOCK_DGRAM aren’t reliable, and data read by the receiver can be out-of-order from the sender’s writes.
Why is this important? Networks are a best-effort delivery system. There’s no guarantee that your data will reach its destination or that you’ll receive what’s been sent to you.
The left-hand column represents the server. On the right-hand side is the client.
Starting in the top left-hand column, note the API calls the server makes to setup a “listening” socket:
socket() bind() listen() accept()
A listening socket does just what it sounds like. It listens for connections from clients. When a client connects, the server calls accept() to accept, or complete, the connection.
The client calls connect() to establish a connection to the server and initiate the three-way handshake. The handshake step is important since it ensures that each side of the connection is reachable in the network, in other words that the client can reach the server and vice-versa. It may be that only one host, client or server, can reach the other.
In the middle is the round-trip section, where data is exchanged between the client and server using calls to send() and recv().
At the bottom, the client and server close() their respective sockets.
二 Sticky package
Sticky package and sticky package solution of python Packet sticking mainly occurs in TCP connection. When a socket client based on TCP uploads a file to the server, the content of the file is sent according to a segment of byte stream. In the eyes of the receiver, it doesn't know where the byte stream of the file starts or ends at all
There are two kinds of sticking phenomenon:
1 consecutive packets may be sent together by optimization algorithm
2 if the first time the size of the data sent is 2000B, and the receiving end accepts the size of 1024 at one time, the rest of the content will be received by the next recv, resulting in confusion of the results
三 Solutions to the sticky phenomenon
Scheme 1:
because both parties don't know the length of the data sent by the other party, they may not receive completely or receive the information content sent in another time. Therefore, before sending the real data, the length of the data should be sent first. The receiving end receives the real data according to the length, but both parties have a process of mutual confirmation
# Server side
import socket
import subprocess
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
#Receiving system instructions from the client,My server passes subprocess The module executes this instruction in the server's own system
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #Where to store the correct results
stderr=subprocess.PIPE #Storage location of error results
)
#Take the results out of the pipe,adopt subprocess.Popen Instanced objects for.stdout.read()Method to get the results in the pipeline
std_msg = sub_obj.stdout.read()
#In order to solve the sticking phenomenon,We counted the length of the message,Send the length of the message to the client first,The client receives the real data to be sent later through this length
std_msg_len = len(std_msg)
# std_bytes_len = bytes(str(len(std_msg)),encoding='utf-8')
#First, convert the data type of data length to bytes type
std_bytes_len = str(len(std_msg)).encode('utf-8')
print('Execution result length of instruction>>>>',len(std_msg))
conn.send(std_bytes_len)
status = conn.recv(1024)
if status.decode('utf-8') == 'ok':
conn.send(std_msg)
else:
pass
# Client
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('Please input the instruction:')
client.send(cmd.encode('utf-8'))
server_res_len = client.recv(1024).decode('utf-8')
print('Message length from server',server_res_len)
client.send(b'ok')
server_cmd_result = client.recv(int(server_res_len))
print(server_cmd_result.decode('gbk'))
Scheme 2:
Struct module,
Package: struct.pack('i ', length)
Unpack: struct.unpack('i ', bytes)
# Server side
import socket
import subprocess
import struct
server = socket.socket()
ip_port = ('127.0.0.1',8001)
server.bind(ip_port)
server.listen()
conn,addr = server.accept()
while 1:
from_client_cmd = conn.recv(1024)
print(from_client_cmd.decode('utf-8'))
#Receiving system instructions from the client,My server passes subprocess The module executes this instruction in the server's own system
sub_obj = subprocess.Popen(
from_client_cmd.decode('utf-8'),
shell=True,
stdout=subprocess.PIPE, #Where to store the correct results
stderr=subprocess.PIPE #Storage location of error results
)
#Take the results out of the pipe,adopt subprocess.Popen Instanced objects for.stdout.read()Method to get the results in the pipeline
std_msg = sub_obj.stdout.read()
#In order to solve the sticking phenomenon,We counted the length of the message,Send the length of the message to the client first,The client receives the real data to be sent later through this length
std_msg_len = len(std_msg)
print('Execution result length of instruction>>>>',len(std_msg))
msg_lenint_struct = struct.pack('i',std_msg_len)
conn.send(msg_lenint_struct+std_msg)
# Client
import socket
import struct
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
cmd = input('Please input the instruction:')
#Send instruction
client.send(cmd.encode('utf-8'))
#Received data length,Receive 4 bytes of data first,Because these four bytes are length
server_res_len = client.recv(4)
msg_len = struct.unpack('i',server_res_len)[0]
print('Message length from server',msg_len)
#Length by unpacking,To receive the real data
server_cmd_result = client.recv(msg_len)
print(server_cmd_result.decode('gbk'))