Select module in Python and I/O Multiplexing

Overview:

  • I/O multiplexing enables programs to be registered with the Operating System kernel for them to be notified of one or more I/O conditions.
  • Programs often use I/O multiplexing when the number of descriptors involved is more. Example: A server program handling multiple sockets.
  • The select module of Python provides low level I/O multiplexing routines provided by most of the operating systems, like select() and poll().
  • The module also provides methods that are specific to certain operating systems like Solaris and BSD.

Example - Using select for I/O multiplexing in Python:

Echo Client:

import socket

import select # For I/O multiplexing

import sys

 

def readServerWriteToStdOut(socketDesc):

    data = socketDesc.recv(1024)

    #print("Received from Server: %s"%(data))

    print(data)

   

def readStdInWriteToServer(inputDesc,data2Svr):

    bytes    = str.encode(data2Svr)

    inputDesc.sendall(bytes)

   

# Create a socket instance

echoSocket = socket.socket()

 

# Obtain the descriptor of the socket

socketDesc = echoSocket.fileno()

 

# Obtain the descriptor of the standard input

inputDesc  = sys.stdin.fileno()

 

# Using the socket connect to the echo server...in this case localhost

echoSocket.connect(("localhost", 32768))

print("Connected to echo server at local host")

 

readDescriptors         = []

readDescriptors.append(socketDesc)

readDescriptors.append(inputDesc)

 

writeDescriptors        = []

execptionDescriptors    = []

try:

    while(True):

        readReady, writeReady, exceptionReady = select.select(readDescriptors, writeDescriptors, execptionDescriptors)

 

        for desc in readReady:

            if desc is socketDesc:

                data = readServerWriteToStdOut(echoSocket)

                break           

 

            if desc is inputDesc:

                data2Svr = input()

                readStdInWriteToServer(echoSocket,data2Svr)

                break

except KeyboardInterrupt:

    echoSocket.shutdown(socket.SHUT_RDWR)

    echoSocket.close()

    pass

Echo Server:

import socket

import os

 

# Create a server socket for the echo server

serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

 

print("Server socket for echo server created")

 

# Associate the server socket of the echo server with the IP address and Port

ipAddress      = "127.0.0.1"

portNumber    = 32768

 

serverSocket.bind((ipAddress, portNumber))

print("Server socket bound with ip address {} on port {}".format(ipAddress, portNumber))

 

# Make the echo server listen for incoming connections

serverSocket.listen()

 

# Serve the incoming connections

echoCount = 0

 

try:

    while(True):

        (clientConnection, clientAddress) = serverSocket.accept()

        echoCount = echoCount + 1

        print("Echo server has served {} connections so far".format(echoCount))

 

        # Read the data sent by echo clients

        while(True):

            data = clientConnection.recv(1024)

            print(data)

            if(data == b''):

                clientConnection.close()

                break;

            sent = clientConnection.sendall(data)

        clientConnection.close()

        print("Connection closed for ip address {}".format(clientAddress))

 

except KeyboardInterrupt:

    pass

 

finally:

    serverSocket.close()   

 

Example-Using select to send to and receive from a HTTP Server in Python:

# import the socket and select modules

import socket

import select

 

# List of descriptors for - Read, Write and Exception

rlist   = []

wlist   = []

xlist   = []

 

# Create a socket instance

socketObject        = socket.socket()

 

# Get the descriptor of the socket object and add to write descriptor list

socketDescriptor    = socketObject.fileno()

wlist.append(socketDescriptor)

 

# Connect to example.com

socketObject.connect(("example.com", 80))

print("Connected to example.com")

 

# Use select and block till the descriptor is ready for write

readReady, writeReady, exceptionOccurred = select.select(rlist, wlist, xlist,0)

 

# Send a http message to example.com and get the home page

if writeReady[0] is socketDescriptor: 

    HTTPMessage         = "GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"

    httpMessageBytes    = str.encode(HTTPMessage)

    socketObject.sendall(httpMessageBytes)

 

# Create a new list

# Removing from wlist and adding to rlist will also work

# However, one can not add the same descriptor to two lists - rlist and wlist

rlist1 = []

wlist1 = []

xlist1 = []

rlist1.append(socketDescriptor)

 

# Use select and block till the descriptor is ready for read

readReady, writeReady, exceptionOccurred = select.select(rlist1, wlist1, xlist1 )

 

# Make sure the descriptor is the one we are interested in

if readReady[0] is socketDescriptor: 

    # Receive the data

    while(True):

        data = socketObject.recv(1024)

        print(data)

 

        if(data==b''):

            print("Connection closed")

            break

 

socketObject.close()

 


Copyright 2024 © pythontic.com