TCP

Python

Level

The Python socket interface is very low level, based directly on the BSD C socket API. This makes it pretty gruesome to work with, just like the C version.

Socket address type

For IPv4, a socket address is a pair (host, port) where the host may be a hostname of an IPv4 address. For IPv6, a socket address is a 4-tuple (host, port, flowinfo, scopeid). The flowinfo filed seems to be still experimental and should be set to zero for now ( Flow Labels). The scopeid can be something like the interface name, I think, needed for link local addresses.

Client

Python uses the type socket to connect to a server. You need to specify the IP protocol, AF_INET for IPv4 or AF_INET6 for IPv6, and the socket such as SOCK_STREAM for TCP. Next, the connection has to be to a (address, port) for IPv4 or to a (address, port, flow info, scope id) tuple for IPv6.

We read strings from stdin. The socket reads and writes are in bytes. The other languages considered here have a default encoding of strings to and from bytes. Python prefers to make it explicit. The topic is discussed further in the chapter on Text but here is given explicit encoding as UTF-8.

The IPv4 client is EchoClient.py illustrates these:



# from https://realpython.com/python-sockets/#echo-client-and-server
#!/usr/bin/env python3

import socket
import fileinput
import sys

PORT = 2000       # The port used by the server

if len(sys.argv) < 2:
    print('Usage: comm hostname')
    exit(1)

host = sys.argv[1]

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((host, PORT))
    print('Enter line:', end='', flush=True)
    for line in sys.stdin: # fileinput.input():
        print("Read line '%s'" % line)
        if line.rstrip() == 'BYE':
            s.close()
            exit(0)

        s.sendall(line.encode('utf-8'))
        data = s.recv(1024)
        print("Received '%s'" % str(data,  encoding='utf-8'))
        print('Enter line:', end='', flush=True)



For IPv6, simply change AF_INET to AF_INET6. This will work in cases that do not involve a scopeid (which will probably only occur if you use ambiguous link local addresses).

Server

There are two mechanisms to write servers. One uses the socket type already considered. The other uses a slightly higher level serversocket module. For the sequential server, we use socket. EchoServer.py illustrates this:


# https://realpython.com/python-sockets/#echo-server
# sequential server

import socket

HOST = '' # INADDR_ANY
PORT = 2000

with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    while True:
        conn, addr = s.accept()
        with conn:
            print('Connected by', addr)
            while True:
                data = conn.recv(1024)
                if not data:
                    print('Disconnecting')
                    break
                conn.sendall(data)

Multi-threaded server

For the multi-threaded server, there are three choices:

We take this code from Write a Multithreaded Server in Python , using threads.

The server is MutiEchoServer.py:


# from https://www.techbeamers.com/python-tutorial-write-multithreaded-python-server/

import socket 
from threading import Thread 
from socketserver import ThreadingMixIn 

# Multithreaded Python server : TCP Server Socket Thread Pool
class ClientThread(Thread): 
 
    def __init__(self,ip,port): 
        Thread.__init__(self) 
        self.ip = ip 
        self.port = port 
        print('Connecing')
 
    def run(self): 
        while True : 
            data = conn.recv(2048) 
            if not data:
                    print('Disconnecting')
                    break
            conn.send(data)

# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0' 
TCP_PORT = 2000 
BUFFER_SIZE = 20  # Usually 1024, but we need quick response 

tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
tcpServer.bind((TCP_IP, TCP_PORT)) 
threads = [] 
 
while True: 
    tcpServer.listen(4) 
    print("Multithreaded Python server : Waiting for connections from TCP clients...")
    (conn, (ip,port)) = tcpServer.accept() 
    newthread = ClientThread(ip,port) 
    newthread.start() 
    threads.append(newthread) 
 
for t in threads: 
    t.join() 

Socket options

Resources


Copyright © Jan Newmarch, jan@newmarch.name
Creative Commons License
" Network Programming using Java, Go, Python, Rust, JavaScript and Julia" by Jan Newmarch is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License .
Based on a work at https://jan.newmarch.name/NetworkProgramming/ .

If you like this book, please contribute using PayPal