Content

  1. Overview
    1. Berkeley UNIX Socket API
    2. What is Socket?
  2. Service Mode
    1. Connection-Oriented (TCP)
    2. Connectionless (UDP)
  3. Port
  4. Python Socket Interface
  5. Network Byte Ordering
  6. Error Handling
  7. Server Concurrency
  8. Other Utility Functions

Overview

Berkeley UNIX Socket API

Berkeley sockets allows you to write network applications on top of TCP or UDP.

What is Socket?

  • An OS abstraction - a bidirectional endpoint
  • Dynamically created by the program during runtime
  • Persists only while application runs
  • Used by the application on all communication operations through the socket

Service Mode

Connection-Oriented (TCP)

  1. Setup logical connection between two peer application processes
  2. Reliable bidirectional in-sequence transfer of byte stream
  3. Multiple send/recv between peer processes
  4. Connection release

Connectionless (UDP)

  1. Destination address written in each message
  2. Immediate transfer of one block of information
  3. No setup overhead & delay
  4. Send/recv to/from multiple peer processes using the same endpoint (UDP socket)
  5. Best-effort service only (possibly out-of-order || loss)

Client-Server Communication

  • Server: passively waiting at know address & port to accept requests
  • Client: actively contacting server requesting for data or service

Port

One per service on a single machine.

  • Range: 0-65535
    • 0 - 1023 reserved for system processes or privileged users
    • 1024 - 49151 ordinary use
    • 49152 - 65535 dynamic or private

Python Socket Interface

  • Create socket

      sockfd = socket.socket([family[,type[,protocol]]])
    
      * family: socket.AF_INET (IPv4) || socket. socket.AF_INET6 (IPv6)
      * type: socket.SOCK_STREAM (TCP) || socket.DGRAM (UDP)
    
  • Bind to an address & port (usually server)

      sockfd.bind( (host,port[,flowinfo,scopeid]) )
    
      * host: hostname (non-deterministic) || IP address || ""
      * flowinfo & scopeid: for IPv6
    
  • Connection setup

    • Server

      • Waiting for incoming connections

          sockfd.listen(backlog)
        
          * backlog: max. number of clients waiting in the queue
          * this socket object is for connection, not communication
        
      • Accepting incoming connections

          conn, addr = sockfd.accept()
        
          * conn: socket object for communication
          * addr: socket address bound to the other end
          * the process is blocked when calling accept()
        
    • Client

      • Connects to server

          sockfd.connect( (host,port) )
        
  • Sending messages

    • TCP

        numOfBytesSent = sockfd.send(bytes[,flags])
      
        * bytes: bytes object (sequence of bytes)
        * numOfBytesSent: might be less then length of bytes object
      
        sockfd.sendall()
      
        * continues to send all bytes until the end || error
      
    • UDP

        numOfBytesSent = sockfd.sendto(bytes,addr)
      
        * addr: (host,port) of the destination
      
  • Receiving messages

    • TCP

        data = sockfd.recv(bufsize[,flags])
      
        * bufsize: max size of data to receive
        * data: bytes object (b'' if connection broken)
      
        numOfBytesReceived = sockfd.recv_into(buffer[,nbytes[,flags]])
      
        * buffer: storing data
        * nbytes: max size of data to receive
      
    • UDP

        data,addr = sockfd.recvfrom(bufsize[,flags])
      
        * addr: (host,port) of the origin
      
        numOfBytesReceived,addr = sockfd.recvfrom_into(buffer[,nbytes[,flags]])
      
  • Termination

      sockfd.close()
    

Network Byte Ordering

For transmission of data unit size more than 1 byte (short, int, ...), need to convert byte order before sending out & after receiving the data due to endianess.

For strings, the basic data unit is unicode character (multi-bytes character), hence need to encode into ASCII or UTF-8 before sending & after receiving.

  • Before sending
    • socket.htons(X) 16-bits
    • socket.htonl(X) 32-bits
  • After receiving
    • socket.ntohs(X)
    • socket.ntohl(X)

Error Handling

try:
    socket.do_something()
except socket.error as err:
    # handle err

Server Concurrency

  • Iterative (sequential) server
    • Accepts & handles 1 client connection at a time
  • Concurrent server
    • Handles multiple client requests at a time
while (True):
    client = sockfd.accept()
    newthd = threading.Thread(target=thd_func, args=(client,))
    newthd.start()

Other Utility Functions

  • sockfd.getpeername() -> (peer_ip,peer_port)
  • sockfd.getsockname() -> (my_ip,my_port)
  • sockfd.gethostname() -> my_hostname
  • sockfd.setsockopt()
    • e.g. sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  • sockfd.getsockopt()
  • sockfd.gethostbyaddr() -> hostname of IP
  • sockfd.getaddrinfo() -> IPs of hostname
  • select.select(): block-wait for multiple active sockets at the same time

results matching ""

    No results matching ""