python select.select module communication process in detail

Keywords: Python socket

To understand the select.select module is essentially to understand its parameters and its three return values.
The select() method receives and monitors three communication lists. The first is all input data, that is, data sent from outside, the second is monitoring and receiving all outgoing data, and the third is monitoring error information.

I've been looking for this parameter explanation of select.select on the internet, but I really don't have it. Ouch..... I've made a hard analysis of it myself.
readable, writable, exceptional = select.select(inputs, outputs, inputs)

The first parameter is the socket on the server side, the second is the socket on the client side that we store in the running process, and the third is the error message.
The focus is on the return value, the first returns a readable list, the second stores a writable list, and the third stores error information.
list.
This does not need to be studied in depth, look at the code under its own analysis can have a general understanding.
All the code about select.select on the Internet is the same, but some of it doesn't work or is incomplete. I've rewritten a working program myself, and I've made a lot of annotations, so I can understand it after a good look.

Server side:

# coding: utf-8
import select
import socket
import Queue
from time import sleep


# Create a TCP/IP
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)

# Bind the socket to the port
server_address = ('localhost', 8090)
print ('starting up on %s port %s' % server_address)
server.bind(server_address)

# Listen for incoming connections
server.listen(5)

# Sockets from which we expect to read
inputs = [server]

# Sockets to which we expect to write
# Processing messages to be sent
outputs = []

# Outgoing message queues (socket: Queue)
message_queues = {}

while inputs:
    # Wait for at least one of the sockets to be ready for processing
    print ('waiting for the next event')
    # start select Monitor, Yes input_list Server side in server Monitor
    readable, writable, exceptional = select.select(inputs, outputs, inputs)

    # Handle inputs
    # Loop to determine if there is a client connection in, When a client connection comes in select Will trigger
    for s in readable:
        # Determine if the current trigger is a server object?, When the triggered object is a server-side object,Explain that a new client is connected in
        # Represents a new user to connect to
        if s is server:
            # A "readable" socket is ready to accept a connection
            connection, client_address = s.accept()
            print ('connection from', client_address)
            # this is connection not server
            connection.setblocking(0)
            # Add client objects to the list of listeners, When the client sends a message select Will trigger
            inputs.append(connection)

            # Give the connection a queue for data we want to send
            # Create a separate message queue for the connected client to store the messages sent by the client
            message_queues[connection] = Queue.Queue()
        else:
            # Old users send messages, Processing acceptance
            # Because the server receives the client connection request when the client connection comes in, the client is added to the listening list.(input_list), Client sending message will trigger
            # So is it a client object trigger?
            data = s.recv(1024)
            # Client not disconnected
            if data != '':
                # A readable client socket has data
                print ('received "%s" from %s' % (data, s.getpeername()))
                # Put the received message into the corresponding socket In the message queue of the client
                message_queues[s].put(data)
                # Add output channel for response
                # A reply operation will be required socket put to output List, Give Way select Monitor
                if s not in outputs:
                    outputs.append(s)
            else:
                # The client disconnected, Listen to the client input List Removal
                # Interpret empty result as closed connection
                print ('closing', client_address)
                # Stop listening for input on the connection
                if s in outputs:
                    outputs.remove(s)
                inputs.remove(s)
                s.close()

                # Remove message queue
                # Remove corresponding socket Message Queuing for Client Objects
                del message_queues[s]

    # Handle outputs
    # If there are no client requests now, When no client sends a message, Start processing the list of sent messages, Do you need to send a message?
    # Store which client sent the message
    for s in writable:
        try:
            # If there is a message in the message queue,Get the message to be sent from the message queue
            message_queue = message_queues.get(s)
            send_data = ''
            if message_queue is not None:
                send_data = message_queue.get_nowait()
            else:
                # The client connection was disconnected
                print "has closed "
        except Queue.Empty:
            # The client connection was disconnected
            print "%s" % (s.getpeername())
            outputs.remove(s)
        else:
            # print "sending %s to %s " % (send_data, s.getpeername)
            # print "send something"
            if message_queue is not None:
                s.send(send_data)
            else:
                print "has closed "
            # del message_queues[s]
            # writable.remove(s)
            # print "Client %s disconnected" % (client_address)

    # # Handle "exceptional conditions"
    # Handling exceptions
    for s in exceptional:
        print ('exception condition on', s.getpeername())
        # Stop listening for input on the connection
        inputs.remove(s)
        if s in outputs:
            outputs.remove(s)
        s.close()

        # Remove message queue
        del message_queues[s]

    sleep(1)

Client:

# coding: utf-8
import socket


messages = ['This is the message ', 'It will be sent ', 'in parts ', ]

server_address = ('localhost', 8090)

# Create aTCP/IP socket

socks = [socket.socket(socket.AF_INET, socket.SOCK_STREAM), socket.socket(socket.AF_INET,  socket.SOCK_STREAM), ]

# Connect thesocket to the port where the server is listening

print ('connecting to %s port %s' % server_address)
# Connect to the server
for s in socks:
    s.connect(server_address)

for index, message in enumerate(messages):
    # Send messages on both sockets
    for s in socks:
        print ('%s: sending "%s"' % (s.getsockname(), message + str(index)))
        s.send(bytes(message + str(index)).decode('utf-8'))
    # Read responses on both sockets

for s in socks:
    data = s.recv(1024)
    print ('%s: received "%s"' % (s.getsockname(), data))
    if data != "":
        print ('closingsocket', s.getsockname())
        s.close()

There are two problems in the process of coding. One is how to judge that the client has closed the socket connection. Then I analyze myself. If the client socket is closed, then the data received by the server is', add this judgment. Second, if the socket is closed on the server side, it will make an error when calling the relevant method of socket, regardless of whether the socket is stored in different containers (that is to say, list_1 stores socket1, list_2 stores socket1, I close socket1, neither of them can call the socket).

Server side:

Client:

Posted by Anti-Moronic on Thu, 23 May 2019 12:59:39 -0700