Socket socket programming

Socket socket programming

 

Today's Content

  • Socket socket programming
    • Simple Server-side and Client-side Code Implementation
  • Communication Cycle
  • Sticky phenomena (TCP protocol)
  • Header making, struct module, encapsulation

Detailed Content

1. Socket socket programming

Implement a program that can interact with data.

When they communicate with each other, they have to transfer data through the network, which will certainly involve the operation of the OSI seven-layer protocol. Each time they transfer data, they need to operate the OSI seven-layer protocol, and they will repeat many similar tasks. At this time, socket module appears, encapsulating the operation code of the OSI seven-layer protocol. When we transfer data, we can see that The socket instantiated object can be used to call the operation method quickly and conveniently in the form of a point.

  • socket module

Next, I'll use the socket module to implement the simplest socket programming.

Note: Only when the server is started can the client successfully connect to the server to achieve data exchange.

Server

import socket

# Instantiate a socket object
server = socket.socket()

# Bind an IP +port number to'server (application)'as a unique identity
server.bind(('192.168.11.134', 8080))

# Set up a semi-connection pool with a maximum capacity (number of connections waiting) of 5
server.listen(5)

# Listen, when a client requests a connection, get its socket object and application address (IP+port)
sock, address = server.accept()

# receive data
data = sock.recv(1024)

print(data.decode('utf8'))

# send data
sock.send('elijah is very good'.encode('utf8'))

# Close socket object connected to client
sock.close()

# Close the server's own socket object
server.close()

Client

import socket


# Instantiate the client's socket object
client = socket.socket()

# Clients connect precisely to servers based on IP+port
client.connect(('192.168.11.134', 8080))

# Send data to server
client.send('i am client'.encode('utf8'))

# Receive data returned by the server
data = client.recv(1024)

print(data.decode('utf8'))

# Close Client
client.close()

2. Communication Cycle

Upgrade the Easy Version so that both the server and the client can enter customized information, and do not end the process as soon as the data is transferred, leaving the server listening and ready to connect with the client.

Server

import socket

# Instantiate a socket object
server = socket.socket()

# Bind an IP +port number to'server (application)'as a unique identity
server.bind(('192.168.11.134', 8080))

# Set up a semi-connection pool with a maximum capacity (number of connections waiting) of 5
server.listen(5)

# Listen, when a client requests a connection, get its socket object and application address (IP+port)
sock, address = server.accept()

while True:
    # receive data
    client_data = sock.recv(1024)

    print(client_data.decode('utf8'))

    # send data
    server_data = input('Enter your reply>>>: ')
    sock.send(server_data.encode('utf8'))

Client

import socket


# Instantiate the client's socket object
client = socket.socket()

# Clients connect precisely to servers based on IP+port
client.connect(('192.168.11.134', 8080))

while True:
    # Send data to server
    client_data = input('Enter your information>>>: ')
    client.send(client_data.encode('utf8'))

    # Receive data returned by the server
    data = client.recv(1024)

    print(data.decode('utf8'))

Realize your one-sentence communication:

Code optimization

1,Keep the server listening. When the server replies to an empty message, it disconnects from the current client and returns to listening
2,The message sent by the client cannot be null (avoid both being present) revc Waiting State)
3,Add compatibility code on the server side ( mac linux)
4,Server restart frequently reported port occupancy error
	from socket import SOL_SOCKET, SO_REUSEADDR
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)  # Add before bind
5,Problem of client abnormal shutdown service side error
	Exception Capture

6.Service-side link loop
7.Semi Connection Pool
	Set the number of clients you can wait on (exceeding this number will cause an error)

Server

import socket

# Instantiate a socket object
server = socket.socket()

# Bind an IP +port number to'server (application)'as a unique identity
server.bind(('192.168.11.134', 8080))

# Set up a semi-connection pool with a maximum capacity (number of connections waiting) of 5
server.listen(5)

while True:
    # Listen, when a client requests a connection, get its socket object and application address (IP+port)
    sock, address = server.accept()

    while True:
        # Handle client unexpected disconnection errors
        try:
            # receive data
            client_data = sock.recv(1024)

            print(client_data.decode('utf8'))

            # send data
            server_data = input('Enter your reply>>>: ')
            if len(server_data) == 0:
                break
            sock.send(server_data.encode('utf8'))
        except Exception as e:
            print(e)
            break

Client

import socket


# Instantiate the client's socket object
client = socket.socket()

# Clients connect precisely to servers based on IP+port
client.connect(('192.168.11.134', 8080))

while True:
    # Send data to server
    client_msg = input('Enter your information>>>: ')
    if len(client_msg) == 0:
        continue
    client.send(client_msg.encode('utf8'))

    # Receive data returned by the server
    data = client.recv(1024)

    print(data.decode('utf8'))

3. sticking problem

Since TCP is also a streaming protocol, data is streamed

When a client initiates a command request to the server, the server returns a large amount of data, while the client only receives 1024 bytes at a time. Obviously, the reception is incomplete, and the remaining data will not be lost, but will be blocked in the transmission channel. When the client next initiates the request command, the remaining data will flow in, causing unanswered questions to be answered.

TCP protocol has a feature

When sending less data, sending more than once, and sending at shorter intervals
 that TCP Automatically packages all this data into a single packet to receive


sock.send('litle')
sock.send('ll')
sock.send('a')

client.recv()
client.recv()
client.recv()
---> litlella

Solve sticking problem

  • Make headlines

Headers are used to identify specific information about upcoming data

For example, the size of the data so that the recipient can decide how much data to receive based on the size of the data

client.recv(4343534)

Simple version header

import socket
import subprocess
import json
import struct

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

while True:
    sock, address = server.accept()
    while True:
        data = sock.recv(1024)  # Receive cmd commands
        command_cmd = data.decode('utf8')
        sub = subprocess.Popen(command_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        res = sub.stdout.read() + sub.stderr.read()  # The result may be great
        # 1. Make headlines
        data_first = struct.pack('i', len(res))
        # 2. Send headers
        sock.send(data_first)
        # 3. Send real data
        sock.send(res)
     
import socket
import struct

client = socket.socket()  # Buy a mobile phone
client.connect(('127.0.0.1', 8080))  # dial

while True:
    msg = input('Please enter cmd command>>>:').strip()
    if len(msg) == 0:
        continue
    client.send(msg.encode('utf8'))
    # 1. Receive header data of a fixed length of 4 first
    recv_first = client.recv(4)
    # 2. Parse headers
    real_length = struct.unpack('i',recv_first)[0]
    # 3. Receive real data
    real_data = client.recv(real_length)
    print(real_data.decode('gbk'))

The header can be made into a dictionary so that in addition to receiving the specific size of the data, it can also receive more information about the data, and the'i'mode when strut is packaged will not cause the data to be too large and error

Expand knowledge

While reading the source code
	1.A colon after a variable name means the type of data the variable name needs to refer to
    2.The greater horizontal bar after the function is greater than the sign means the return value type of the function
 
Label: python

Added by gofeddy on Wed, 12 Jan 2022 21:51:07 +0200