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()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.
Now, we’ll use this illustration to explain the functionality of different socket programming methods.
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.
Here we have a naive implementation of a client-server chat app using python socket programming.
client.pyclient.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):
__init__: Here, the server’s port and address are initialized. Moreover, the client’s socket is initialized and bound to a random port.
join: This method sends the join-message to the server when the client code is run for the first time.
send_message: This method sends the message entered by the client to the server – the server then forwards it to the recipient.
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.
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.pyserver.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):
__init__: Here, the server’s socket is initialized and, by default, bound to address localhost and port 11000.
forward_message: This method forwards the message to the recipient that server receives from the sender.
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.
python3 server.py
You have successfully started the server.
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()
Free Resources