Python Network Programming

1, tcp basic syntax

The server communicates with the client through socket. In order to ensure data integrity, tcp protocol needs to shake hands three times, and can only communicate with one client at a time

Server side writing method:

# Server
#Import socket module
import socket
#Create socket object
sk=socket.socket()
#Bind server IP port
sk.bind(("127.0.0.1",8080))
#Enable server listening status
sk.listen()
#Create tcp triple handshake (conn is the established two-way connection object)
conn,addr=sk.accept()
#Receive data (the maximum allowable transmission size is 1024 bytes)
res=conn.recv(1024)
print(res.decode("utf-8"))
#Turn off two-way connection
conn.close()
#Close socket object
sk.close()

Client writing:

# client
#Import socket module
import socket
#Generate socket object
sk=socket.socket()
#Establish connection with the server
sk.connect(("127.0.0.1",8080))
#send message
sk.send("It rained heavily in Beijing yesterday".encode("utf-8"))
#Close socket
sk.close()

Operation results:

2, tcp circular message sending

The while loop needs to be introduced to send messages circularly to realize the online chat function
Server:

# Server
# Import socket module
import socket
#Create socket object
sk=socket.socket()
#Bind server address and port
sk.bind(("127.0.0.1",8090))
#Listening port
sk.listen()
#Receiving and sending data
while True:
	conn,addr=sk.accept()
	while True:
		res=conn.recv(1024)
		print(res.decode())
		strvar=input("Please enter a message to send to the client:")
		conn.send(strvar.encode())
		if strvar.upper() == "Q":
			break
#Turn off bidirectional connection object
conn.close()
#Close socket object
sk.close()

client:

# client
#Import socket module
import socket
#Create socket object
sk=socket.socket()
#Connect server
sk.connect(("127.0.0.1",8090))
#Sending and receiving data
while True:
	strvar=input("Please enter the information sent to the server:")
	sk.send(strvar.encode())
	res=sk.recv(1024)
	print(res.decode())
	if res == b"q" or res == b"Q":
		break
sk.close()

Operation results:
Server:

client:

3, udp basic syntax

Server:

# Server
# Import socket object
import socket
# When you create a socket object, you need to add parameters because the default is to create a tcp connection
sk=socket.socket(type=socket.SOCK_DGRAM)
# Bind server address and port
sk.bind(("127.0.0.1",9005))
# receive data 
msg,cli_addr=sk.recvfrom(1024)
print(msg.decode())
# send data
strvar="Welcome"
sk.sendto(strvar.encode(),cli_addr)
#Close socket object
sk.close()

client:

# client
import socket
#Create socket object
sk=socket.socket(type=socket.SOCK_DGRAM)
#send data
sk.sendto("Hello".encode(),("127.0.0.1",9005))
#receive data 
msg,server_addr=sk.recvfrom(1024)
print(msg.decode())
#Close connection
sk.close()

Operation results:
Server:

client:

4, udp circular message sending

Under udp protocol, the server can communicate with multiple clients
Server:

# Server
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
sk.bind(("127.0.0.1",9010))
while True:
	msg,cli_addr=sk.recvfrom(1024)
	print(msg.decode())
	strvar=input("Please enter a message to send to the client:")
	sk.sendto(strvar.encode(),cli_addr)
sk.close()

Client 1:

# client
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
while True:
	strvar=input("Please enter the message to be sent to the server:")
	sk.sendto(strvar.encode(),("127.0.0.1",9010))
	msg,server_addr=sk.recvfrom(1024)
	print(msg.decode())
sk.close()

Client 2:

# client
import socket
sk=socket.socket(type=socket.SOCK_DGRAM)
while True:
	strvar=input("Please enter the message to be sent to the server:")
	sk.sendto(strvar.encode(),("127.0.0.1",9010))
	msg,server_addr=sk.recvfrom(1024)
	print(msg.decode())
sk.close()

Operation results:
Server running result:

Client 1 running result:

Client 2 running result:

5, Sticky bag

1. Sticky bag

First, let's look at a situation:
Server:

# Server
import socket
sk=socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen()
conn,addr=sk.accept()
conn.send("Hello".encode())
conn.send("Welcome".encode())
conn.close()
sk.close()

client:

# client
import socket
sk=socket.socket()
sk.connect(("127.0.0.1",8080))
res1=sk.recv(1024)
print(res1.decode(),"<1>")
res2=sk.recv(1024)
print(res2.decode(),"<2>")
sk.close()

Operation results:

As shown in the figure, the "welcome" string that should have been output in the second line and the "hello" string in the first line are output by adhesion. This phenomenon is called sticky package

There are two cases of sticking:

  • Sticking phenomenon I:
    At the transmitting end, because the two data are short and the transmission time interval is short, sticky packets are formed at the transmitting end
  • Sticking phenomenon II:
    At the receiving end, since the two data are sent to each other's cache almost at the same time, all sticky packets are formed at the receiving end

Comparison of sticky packets: tcp and udp

tcp protocol:
Disadvantages: there is no boundary between the data when receiving. It is possible to glue several pieces of data into one piece of data, resulting in sticky packets
Advantages: the size of data packets is not limited, and the transmission is stable without packet loss

udp protocol:
Advantages: there are boundaries between data when receiving, fast transmission speed and no sticky packets
Disadvantages: limit the size of data packets (affected by factors such as bandwidth router), unstable transmission and possible packet loss

2. struct module

Application scenario:

  • Solve the sticky package scenario:
    During real-time communication in the application scenario, you need to read the message sent this time
  • There is no need to solve the sticky package scenario:
    When downloading or uploading files, finally combine the packages together. It doesn't matter to stick the package

pack:
Converts a number of arbitrary length into a byte stream with a fixed length of 4 bytes
Package range: - 2147483648 ~ 2147483647 about 2.1 billion
unpack:
I = > convert the corresponding data to int integer
Restore the four byte value to the original number and return the final tuple

Server:

# Server
import socket
import struct
sk=socket.socket()
sk.bind(("127.0.0.1",8080))
sk.listen()
conn,addr=sk.accept()
strvar="Hello".encode()
res1=len(strvar)
num=struct.pack("i",res1)
#4-bit byte stream transmitted for the first time
conn.send(num)
#Real byte stream transmitted for the second time
conn.send(strvar)
conn.send("Welcome".encode())
conn.close()
sk.close()

client:

# client
import socket
import struct
sk=socket.socket()
sk.connect(("127.0.0.1",8080))
res1=sk.recv(1024)
#Unpack, n is the real length of the incoming data
n=struct.unpack("i",res1)
#The boundary is stuck according to the real length of the string. Note that n is a tuple
res2=sk.recv(n[0])
print(res2.decode(),"<1>")
res3=sk.recv(1024)
print(res3.decode(),"<2>")
sk.close()

Client running result:
Because the boundary is blocked by the struct module in the first packet transmission, there will be no packet sticking

Tags: Python

Posted by Kitkat on Mon, 23 May 2022 02:16:35 +0300