Trusted answers to developer questions
Trusted Answers to Developer Questions

Related Tags

networking
communication
python
python3
socket programming

Socket programming in Python

Educative Answers Team

Grokking Modern System Design Interview for Engineers & Managers

Ace your System Design Interview and take your career to the next level. Learn to handle the design of applications like Netflix, Quora, Facebook, Uber, and many more in a 45-min interview. Learn the RESHADED framework for architecting web-scale applications by determining requirements, constraints, and assumptions before diving into a step-by-step design process.

Answers Code
svg viewer

Introduction

Sockets are endpoints in bi-directional communications between two processes.

Sockets allow us to connect, send, and receive messages across a network. The network can be logical, local, or external. A socket connects and then uses the read() and write() commands the same way that file-descriptors use files and pipes.

Python has a library for socket programming that provides an interface to the Berkeley sockets API. You can import the socket library by writing:

import socket

Some fundamental python socket API methods are:

  • socket()
  • bind()
  • listen()
  • accept()
  • connect()
  • send()
  • recv()
  • close()

TCP and UDP sockets

Before you can use any other socket function, you need to create a socket. To create a socket, we use the socket() method. It is up to the user to create either a TCP socket or a UDP socket.

Compared to a UDP socket, a TCP socket is more reliable and provides in-order data delivery. However, UDP sockets deliver messages faster. It is advised that you use a TCP socket to achieve best-effort delivery from the underlying network.

Creating a TCP socket:

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

Creating a UDP socket:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

socket.AF_INET is used to designate the type of addresses our socket can communicate with which, in this case, is ipv4 addresses. socket.SOCK_STREAM specifies a TCP socket and socket.SOCK_DGRAM specifies a UDP socket.

Exploring fundamental socket programming methods

Now, ​we’ll use this illustration to explain the functionality of different socket programming methods.

svg viewer
  • Both the server and client first create a socket to communicate with other processes. To create a socket, we use the socket() method.

  • Server needs to bind its socket to a specific port and IP. This port and IP will be used by the server to send and receive messages. Use the bind() method to bind the socket.

  • After binding to a defined port and IP, the server needs to listen for incoming connections or messages at this port and IP. Use the listen() method to listen through the socket.

  • For a client to communicate with the server, it first needs to connect to it. Use the connect() method to connect to a port and IP.

  • Before proceeding with the exchange of messages, the server needs to accept the request of a client to connect. Use the accept() method to accept a connection.

  • After the connection is established, both the server and client can exchange messages. U se the send() and recv() method to exchange messages.

  • Both server and client can close a socket and terminate the connection. Use the close() method to close the socket.

To learn more about socket programming in python, visit the official documentation.

Client-server example

Here we have a naive implementation of a client-server chat app using python socket programming.

client.py

client.py consists of a Client class that takes care of the client-side implementation of the chat app. There are five methods (including the constructor):

  1. __init__: Here, the server’s port and address are initialized. Moreover, the client’s socket is initialized and bound to a random port.

  2. join: This method sends the join-message to the server when the client code is run for the first time.

  3. send_message: This method sends the message entered by the client to the server – the server then forwards it to the recipient.

  4. start: This method is called at the start of the code. It calls either the join method or the send_message method depending on the input signal.

  5. receive_handler: This method receives the message from the server and prints it on the terminal. It is called using a thread object in order to run it parallel to the start method.

server.py

server.py consists of a Server class that takes care of the server-side implementation of the chat app. There are three methods (including the constructor):

  1. __init__: Here, the server’s socket is initialized and, by default, bound to address localhost and port 11000.

  2. forward_message: This method forwards the message to the recipient that server receives from the sender.

  3. start: This method is called upon at the start of the code. This method saves the port and address of the client if it receives a join signal, and forwards the message to the recipient if it receives a send_message signal from a the sender.

How to run the chat app

  • Press the blue button underneath the code written below.
  • Once you see the terminal, write the following command and press enter:
python3 server.py

You have successfully started the server.

  • Now, to connect a client to the server, open another terminal and write:
cd usercode

then write

python3 client.py -u Sherlock

You have successfully connected a client named Sherlock to the server.

Sherlock is not going to talk to himself, therefore, let’s make another client named Watson:

python3 client.py -u Watson

To send the message from the client terminal, follow this format:

msg {NameOfClient} {ActualMsg}

For example, you can run this command in the terminal of Sherlock:

msg Watson Education never ends, Watson. It is a series of lessons, with the greatest for the last.

Have fun chatting!

import socket
import sys
import random
from threading import Thread
import getopt



class Client:
    '''
    This is the main Client Class. 
    '''
    def __init__(self, username, dest, port):
        self.server_addr = dest
        self.server_port = port
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.bind(("", random.randint(10000, 40000)))
        self.name = username

    def join(self):
        join_message = "join" + " " + self.name
        self.sock.sendto(join_message.encode("utf-8"),(self.server_addr,self.server_port))
    
    def send_message(self, msg):
        actual_message = "send_message" + " " + msg
        self.sock.sendto(actual_message.encode("utf-8"),(self.server_addr,self.server_port))
    
    def start(self):
        '''
        Main Loop is here
        Start by sending the server a JOIN message.
        Waits for userinput and then process it
        '''
        self.join()

        while True:
            userinput = input()

            input_recv = userinput.split()

            if input_recv[0] == "msg":
                self.send_message(" ".join(input_recv[1:]))
            
            else:
                print("incorrect userinput format")
                continue            

    def receive_handler(self):
        '''
        Waits for a message from server and process it accordingly
        '''

        while True:
            server_message, server_addr_port = self.sock.recvfrom(4096)
            server_message = server_message.decode("utf-8")
            datalist = server_message.split()

            if datalist[0] == "forward_message":
                msg_recv_list = datalist[1:]
                msg_recv = " ".join(msg_recv_list)
                print(msg_recv) 
            
if __name__ == "__main__":
    DEST = 'localhost'
    PORT = 11000

    try:
        OPTS, ARGS = getopt.getopt(sys.argv[1:],
                                   "u:", ["user="])
    except:
        print("Wrong command entered.")
        exit(1)

    USER_NAME = None
    for o, a in OPTS:
        if o in ("-u", "--user="):
            USER_NAME = a

    if USER_NAME is None:
        print("Missing Username.")
        exit(1)

    S = Client(USER_NAME, DEST, PORT)
    try:
        # Start receiving Messages
        T = Thread(target=S.receive_handler)
        T.daemon = True
        T.start()
        # Start Client
        S.start()
    except (KeyboardInterrupt, SystemExit):
        sys.exit()

RELATED TAGS

networking
communication
python
python3
socket programming
Copyright ©2022 Educative, Inc. All rights reserved

Grokking Modern System Design Interview for Engineers & Managers

Ace your System Design Interview and take your career to the next level. Learn to handle the design of applications like Netflix, Quora, Facebook, Uber, and many more in a 45-min interview. Learn the RESHADED framework for architecting web-scale applications by determining requirements, constraints, and assumptions before diving into a step-by-step design process.

Answers Code
Keep Exploring