1, socket module
socket introduction
Socket is an intermediate software abstraction layer for communication between application layer and TCP/IP protocol family. It is a group of interfaces. In the design mode, socket is actually a facade mode. It hides the complex TCP/IP protocol family behind the socket interface. For users, a group of simple interfaces is all, allowing the socket to organize data to comply with the specified protocol.
socket simple code (taking C/S architecture as an example)
Server
import socket server = socket.socket() server.bind(('127.0.0.1', 8090)) server.listen(5) sock, addr = server.accept() print(addr) data = sock.recv(1024) print(data) sock.send(b'hahaha') sock.close() server.close()
Client
import socket client = socket.socket() client.connect(('127.0.0.1', 8090)) client.send(b'xixixi') data = client.recv(1024) print(data) client.close()
Optimized version
1. Client verification message cannot be empty
2. Add compatibility code to the server (mac linux)
Add if recv ==0: continue on the server side
3. The server restarts frequently and reports port occupation error
from socket import SOL_SOCKET, SO_REUSEADDR
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # before bind
4. The client closes abnormally and the server reports an error
Using exception capture
Server
import socket import struct import json server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: sock, addr = server.accept() while True:data = sock.recv(1024) print(data) sock.send(b'hahaha') sock.close() server.close()
Client
import socket client = socket.socket() client.connect(('127.0.0.1', 8090)) client.send(b'xixixi') data = client.recv(1024) print(data) client.close()
2, struct module
struct module can solve the problem of sticking package during file transfer
What is a sticky bag?
During data transmission, the data is not completely transmitted and remains in the pipeline.
For example, a tcp based socket client uploads a file to the server. When sending, the file content is sent according to a segment by segment byte stream. When the receiver sees it, he doesn't know where the byte stream of the file starts and ends
In addition, the sticky packet caused by the sender is caused by the TCP protocol itself. In order to improve the transmission efficiency, the sender often needs to collect enough data before sending a TCP segment. If there is little data that needs to be sent for several consecutive times, TCP will usually be optimized according to algorithm These data are combined into a TCP segment and sent out at one time, so that the receiver receives the sticky packet data.
Solve the sticking problem (take the data transmission code above as an example)
Server
import socket import struct import json server = socket.socket() server.bind(('127.0.0.1', 8080)) server.listen(5) while True: sock, addr = server.accept() while True: head_data = sock.recv(4) # Parse header dict_length = struct.unpack('i', head_data)[0] # Receive dictionary dict_data = sock.recv(dict_length) # Deserialize dictionary and decode dict_real = json.loads(dict_data) # Gets the file size in the dictionary file_size = dict_real.get('size') file_name = dict_real.get('filename') # Upload file recv_size = 0 with open('filename', 'wb') as f: while recv_size < file_size: data = sock.recv(1024) recv_size += len(data) f.write(data)
Client
import os import socket import json import struct client = socket.socket() client.connect(('127.0.0.1', 8080)) while True: data_path = r'D:\BaiduNetdiskDownload\video' movie_list = os.listdir(data_path) for i, j in enumerate(movie_list, 1): print(i, j) choice = input('Please enter the number>>>: ') if choice == 0: continue if choice.isdigit(): choice = int(choice) if choice in range(1, len(movie_list) + 1): movie_name = movie_list[choice - 1] movie_path = os.path.join(data_path, movie_name) data_dict = { 'size': os.path.getsize(movie_path), 'filename': movie_name } data_josn = json.dumps(data_dict) data_head = struct.pack('i', len(data_josn)) client.send(data_head) client.send(data_josn.encode('utf8')) with open(movie_path, 'rb') as f: for line in f: client.send(line)