Content
- Overview
- Berkeley UNIX Socket API
- What is Socket?
- Service Mode
- Connection-Oriented (TCP)
- Connectionless (UDP)
- Port
- Python Socket Interface
- Network Byte Ordering
- Error Handling
- Server Concurrency
- 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)
- Setup logical connection between two peer application processes
- Reliable bidirectional in-sequence transfer of byte stream
- Multiple send/recv between peer processes
- Connection release
Connectionless (UDP)
- Destination address written in each message
- Immediate transfer of one block of information
- No setup overhead & delay
- Send/recv to/from multiple peer processes using the same endpoint (UDP socket)
- 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-bitssocket.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_hostnamesockfd.setsockopt()
- e.g.
sockfd.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- e.g.
sockfd.getsockopt()
sockfd.gethostbyaddr()
-> hostname of IPsockfd.getaddrinfo()
-> IPs of hostnameselect.select()
: block-wait for multiple active sockets at the same time