socket and struct module

Posted by activeradio on Wed, 12 Jan 2022 19:25:30 +0100

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)