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)