Python---socket module usage

socket module

Introduction to socket

To write a cs architecture program to realize data interaction, you need to write code to operate OSI seven layers, which is quite complex. Since the operation of OSI layer 7 is a process that all cs architecture programs need to go through, there are fixed modules. Socket socket is a technology. The socket module provides a shortcut and does not need to deal with each layer by itself.

socket module application

cs architecture software, whether in writing or running, should first consider the service side, that is, to open a store, you have to have an existing store to receive guests.

Server

import socket  # Import socket module

server = socket.socket()  # Buy a mobile phone
"""
By looking at the source code 
If no parameters are written in parentheses, the default is network-based compliance TCP Protocol socket
"""
server.bind(('127.0.0.1', 8080))  # Insert telephone card
"""
Characteristics of the server
    Fixed address
127.0.0.1 Is the local loopback address of the computer, which can only be accessed by the current computer itself
"""
server.listen(5)  # Power on
"""
Semi connection pool---Setting the maximum waiting number can save resources and improve efficiency
"""
sock, addr = server.accept()  # Waiting for no one to come
"""
listen and accept corresponding TCP Two states of the three handshake server
"""
print(addr)  # Address of the client
data = sock.recv(1024)  # Listen to others
print(data.decode('utf8'))
sock.send('How do you do'.encode('utf8'))  # Reply to what others say
"""
recv and send Both received and sent bytes Type of data
"""
sock.close()  # Hang up
server.close()  # Shut down

client

import socket

client = socket.socket()  # Generate a socket object
client.connect(('127.0.0.1', 8080))  # Link according to the address of the server

client.send(b'hello sweet heart!!!')  # Send a message to the server
data = client.recv(1024)  # Receive the message replied by the server
print(data.decode('utf8'))

client.close()  # Close client

'''
First interaction between server and client
	On one side recv Then the other side must be send  Both sides cannot be the same, otherwise'Cold War'Yes
'''

recv and send receive and send bytes of data.

When the server interacts with the client for the first time, one side is recv, and the other side must be send. Both sides cannot be the same, otherwise both sides are waiting for messages from the other side and get stuck directly.

Semi connection pool

By default, the py file can only be run once at a time. If you want to run multiple times separately, you need to use a semi connection pool.

Function: setting the maximum waiting number can save resources and improve efficiency.

server.listen(5)  

Communication cycle

To solve the problem of message fixation, this is simple. You can directly use the input method to obtain the message input by the user. In order to enable the server and client to send messages to each other all the time, we need to solve the problem of communication cycle. Communication cycle is mainly a cycle, which can be realized by using while cycle.

Server

while True:
    data = sock.recv(1024)  # Listen to others
    print(data.decode('utf8'))
    msg = input('Please reply to the message>>>:').strip()
    sock.send(msg.encode('utf8'))  # Reply to what others say

client

while True:
    msg = input('Please enter the message you need to send>>>:').strip()
    client.send(msg.encode('utf8'))  # Send a message to the server
    data = client.recv(1024)  # Receive the message replied by the server
    print(data.decode('utf8'))

Code optimization and link loop

We can count the length of occurrence for judgment to avoid empty information.

# client
while True:
    msg = input('Please enter the message you need to send>>>:').strip()
    # If the user does not enter anything and simply enters the vehicle, he should not go down
    if len(msg) == 0:
        continue
    client.send(msg.encode('utf8'))  # Send a message to the server
# Server
msg = input('Please reply to the message>>>:').strip()
            if len(msg) == 0:
                msg = 'Too busy. No news yet'

Repeated restart of the server may result in an error, address in use. The mistake is that Apple reports frequently and windows reports less frequently. We can use the following code to solve the repeated restart error.

from socket import SOL_SOCKET,SO_REUSEADDR
  server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) # Add before bind

On windows, after the client exits abnormally, the server will directly report an error. We can adopt the method of exception handling. If it is a mac or linux system, the server will receive an empty message. We can use the method of len length judgment to solve it.

Code demonstration

    while True:
        try:
            data = sock.recv(1024)  # Listen to others
            if len(data) == 0:
                break
            print(data.decode('utf8'))
            msg = input('Please reply to the message>>>:').strip()
            if len(msg) == 0:
                msg = 'Too busy. No news yet'
            sock.send(msg.encode('utf8'))  # Reply to what others say
        except Exception:
            break
'''
 If the client is disconnected abnormally, the server code should return to accept Waiting for new guests
 '''

Sticking problem

The characteristic of TCP protocol is that it will send the data with small amount of data and short time interval together, and it will also be subject to the number in recv brackets. Because TCP protocol is a streaming protocol, which is as uninterrupted as water flow.

data1 = conn.recv(1024)
print(data1)
data2 = conn.recv(1024)
print(data2)
data3 = conn.recv(1024)
print(data3)

client.send(b'hello')
client.send(b'jason')
client.send(b'kevin')
"""
Results of three prints
  b'hellojasonkevin'
  b''
  b''
"""
# Problem: three incoming data are combined into one

The reason for the problem is that we don't know the size of the data to be received in recv brackets. If we can accurately know the size of the data received each time, there will be no sticky packets.

Idea: if you accurately know the amount of data, the sticking problem will be solved automatically.

Solve the sticking problem

The struct module can be used to accurately obtain the size of data.

Idea:
1. First package the real data into a fixed length package
2. Send the fixed length package to the other party first
3. After receiving the packet, the other party unpacks to obtain the real data length
4. received real data length

import struct

data1 = 'hello world!'
print(len(data1))  # 12
# Pack can pack numbers of any length into a fixed length
res1 = struct.pack('i', len(data1))  # The first parameter is the format. Just write i
print(len(res1))  # 4
#  Unpack can unpack a fixed length number into the actual length of the data before packaging
ret1 = struct.unpack('i', res1)
print(ret1)  # (12,)

data2 = 'hello baby baby baby baby baby baby baby baby'
print(len(data2))  # 45
res2 = struct.pack('i', len(data2))
print(len(res2))  # 4
ret2 = struct.unpack('i', res2)
print(ret2)  # (45,)

Small problem: the method responsible for packaging cannot be packaged if the amount of data is particularly huge.

The ultimate solution: using a dictionary to store data not only has the length of the data, but also can carry additional data.

Idea of sender:

 1.First construct a dictionary 
        Information related to real data is archived internally
            Size name introduction ...
2.Package the dictionary
3.Fixed length data(Dictionaries)Send to the other party
4.Send real dictionary data
5.Send real data

Idea of receiving end:

1.Receive a fixed length dictionary packet first
2.Parse out the true length of the dictionary
3.Receive dictionary data
4.Parse various information from dictionary data
5.Receive real data

Code implementation:

# Server
import socket
import os
import struct
import json


server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

conn, addr = server.accept()

data_dict = {
    'file_name':'xxx stimulate.txt',
    'file_desc':'Sealed up for more than a month',
    'file_size':os.path.getsize(r'04 struct modular.py')
}
# 1. Pack the dictionary first
dict_json_str = json.dumps(data_dict)
dict_bytes = dict_json_str.encode('utf8')
dict_package_header = struct.pack('i', len(dict_bytes))
# 2. Send header
conn.send(dict_package_header)
# 3. Send dictionary
conn.send(dict_bytes)
# 4. Send real data
with open(r'04 struct modular.py', 'rb') as f:
    for line in f:
        conn.send(line)
# client
import socket
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1', 8080))

# 1. First receive the header of a fixed length dictionary
dict_header_len = client.recv(4)
# 2. Analyze the real length of the dictionary
dict_real_len = struct.unpack('i', dict_header_len)[0]
# 3. receive dictionary data
dict_data_bytes = client.recv(dict_real_len)
dict_data = json.loads(dict_data_bytes)
print(dict_data)
# 4. Receive file data circularly, not at one time
recv_size = 0
with open(dict_data.get('file_name'),'wb') as f:
    while recv_size < dict_data.get('file_size'):
        data = client.recv(1024)
        recv_size += len(data)
        f.write(data)

Posted by provision on Fri, 15 Apr 2022 23:43:55 +0930