Sendmsg() method of python socket class

Overview:

  • The sendmsg() function sends non-ancillary data from multiple buffers to a destination socket. It also sends ancillary data if any and the related information as one or more tuples. 

  • The sendmsg() function sends data using TCP, UDP and Unix Domain Protocol.

  • While the sendmsg() sends non-ancillary data by concatenating the contents of multiple bytes like objects, the recvmsg() function sends non-ancillary data by returning a bytes object inside a tuple containing other related information.

  • TCP is a connection oriented protocol where data is streamed between two connected sockets. UDP is a connectionless protocol where data is sent as discrete messages between sockets. Unix domain protocol sends file descriptors across processes in the same machine without using the protocol stack overhead.

sendmsg() function of socket module in Python

Example - Server using Unix domain socket:

The example uses Unix domain sockets and the socket interface to send a text message through non-ancillary data and file descriptors through ancillary data from the client process to the server process running in the same machine. In this mechanism the kernel takes care of providing the valid file descriptors to the other process. It works for processes running in the same machine. Socket instances are created with the adress family socket.AF_UNIX.

The send_fds() and recv_fds() methods of the Python socket class send and receive file descriptors using Unix domain sockets.   

# Example Python server program that
# listens through Unix domain protocol.
# The server receievs file descriptors from
# the client and prints the file contents
import socket
import os
import shutil
import array

# Create Unix domain socket
dx = socket.socket(socket.AF_UNIX)

# Bind the server socket to a path
svrPath = "/ex/svr_fd"
shutil.rmtree(svrPath)
dx.bind(svrPath)

# Listen for incoming connections
dx.listen()
print("Unix domain socket listening...")

while(True):
    # Serve the client connections
    sock, addr = dx.accept()

    fdList = None
    while(True):
        nonAncMsg, ancData, ctrlFlags, fromAddr = sock.recvmsg(1024, socket.CMSG_LEN(8))
        print("Message received at server...")
        print("Non-ancillary message:%s"%nonAncMsg.decode("utf-8"))
        
        # Retrieve the file descriptors back...
        fdArray = array.array("i")
        for ctrlMsgLevel, ctrlMsgType, ctrlMsgData in ancData:
            startIndex = 0
            endIndex = len(ctrlMsgData) - len(ctrlMsgData) % fdArray.itemsize
            bytesRecvd = ctrlMsgData[startIndex:endIndex]
            fdArray.frombytes(bytesRecvd)

        # List of file descriptors        
        fdList = list(fdArray)    
        break

    # The kernel recreated the file descriptors...just use them
    print("Contents of the file descriptor:")    
    fdCount = 0
    for fd in fdList:
        fdCount = fdCount + 1
        print("File %d contents:"%fdCount)
        fileContents =os.read(fd, 1024).decode("utf-8")
        print(fileContents)        

Output:

Unix domain socket listening...

Message received at server...

Non-ancillary message:Temperature data

Contents of the file descriptor:

File 1 contents:

time  temp(in degree Celsius)

00.00 23

01.00 22

02.00 22

03.00 19

04.00 17

05.00 18

06.00 19

07.00 19

08.00 23

 

File 2 contents:

time  temp(in degree Celsius)

00.00 23

01.00 22

02.00 22

03.00 19

04.00 17

05.00 18

06.00 19

07.00 19

08.00 23

Example - Client using Unix domain socket and sendmsg() method:

# Example Python program that sends file
# descriptors using Unix domain protocol 
# and sendmsg() method
import os
import socket
import array

# Create two file descriptors and send them
# to server for reading their contents
hourlyWeather = os.open("./weather.txt", os.O_RDONLY)
hourlyWeather1 = os.open("./weather1.txt", os.O_RDONLY)

# Create a Unix domain socket
sender     = socket.socket(socket.AF_UNIX)
path     = "/ex/svr_fd"

# Connect to the server
sender.connect(path)

# Non-ancillary message for the sendmsg() function
heading    = "Temperature data"
nonAncilMsg  = [str.encode(heading)]

# Ancillary message for the sendmsg() function
ancillaryMsg = [(socket.SOL_SOCKET, 
                 socket.SCM_RIGHTS, 
                 array.array("i", [hourlyWeather, hourlyWeather1]))]

# Send nonAncilMsg + ancillaryMsg to the server
sender.sendmsg(nonAncilMsg, ancillaryMsg)

Output:

Message sent to the server

 


Copyright 2024 © pythontic.com