Multithreaded socket server in Python
A thread is a sequence of such instructions within a program that can be executed independently of other code. A multithreaded program contains two or more parts that can run concurrently. Each part of such a program is called a thread, and each thread defines a separate path of execution. Multithreaded Socket Programming describes that a Multithreaded Socket Server can communicate with more than one client at the same time in the same network.
In the previous lesson Python Socket Programming describes a Server Socket Program can communicate with only one client at a time . That means, the Python Server Socket Program does not accept more than one Client connection . From the following section you can understand how to a Python Multithreaded Server M can communicate with more than one Clients at the same time . You can see the basics of Socket Programming in the previous lesson , before you start this section take a look at Python Socket Programming
Python Multithreaded Socket Programming has two sections:
- Python Multi Threaded Server Socket Program (Server.py)
- Python Client Socket Program (client.py)
import socket, threading class ClientThread(threading.Thread): def __init__(self,clientAddress,clientsocket): threading.Thread.__init__(self) self.csocket = clientsocket print («New connection added: «, clientAddress) def run(self): print («Connection from : «, clientAddress) #self.csocket.send(bytes(«Hi, This is from Server..»,’utf-8′)) msg = » while True: data = self.csocket.recv(2048) msg = data.decode() if msg==’bye’: break print («from client», msg) self.csocket.send(bytes(msg,’UTF-8′)) print («Client at «, clientAddress , » disconnected. «) LOCALHOST = «127.0.0.1» PORT = 8080 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((LOCALHOST, PORT)) print(«Server started») print(«Waiting for client request..») while True: server.listen(1) clientsock, clientAddress = server.accept() newthread = ClientThread(clientAddress, clientsock) newthread.start()
import socket SERVER = «127.0.0.1» PORT = 8080 client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((SERVER, PORT)) client.sendall(bytes(«This is from Client»,’UTF-8′)) while True: in_data = client.recv(1024) print(«From Server :» ,in_data.decode()) out_data = input() client.sendall(bytes(out_data,’UTF-8′)) if out_data==’bye’: break client.close()
How to run this program ?
Create Python Multi Threaded Server Socket Program (Server.py) and Python Client Socket Program (client.py) in two separate files. Open a DOS prompt (console) and run the Server Program first. Then you will get the message «Server started» in Server side. Next you start the Client program in another DOS prompt (console), then you can see the message from Server . Like this , you can start more than one client at the same time from different Dos prompts and communicate with the Server program. The server accept your message and reply the same message to the same client. You can open many client program and test the server reply to each client.
Socket Programming with Multi-threading in Python?
Multithreading is the core concept of nearly all modern programming languages especially python because of its simplistic implementation of threads.
A thread is a sub-program within a program that can be executed independently of other section of the code. A thread executes in the same context sharing program’s runnable resources like memory.
When in a single process, we are executing multiple threads simultaneously, it is called multithreading.
Python Multithreading Modules for a thread implementation
To implements threads in programs, python provides two modules −
Where the thread module creates a thread as a function whereas the threading module provides an object-oriented approach to create a thread.
Syntax
_thread.start_new_thread(func, args[, kwargs])
Above starts a new thread and returns its identifier. The first argument is a function func which the thread executes with the second argument containing a tuple with a positional list of arguments. The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exists.
In this, we see a basic example of a client-server application. Where clients basically open a socket connection and send queries to the server. The server responds back.
On running with no argument, this program starts with a TCP socket server that listens for connections to 127.0.0.1 on port 8000.
import socket import sys def main(): soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "127.0.0.1" port = 8000 try: soc.connect((host, port)) except: print("Connection Error") sys.exit() print("Please enter 'quit' to exit") message = input(" -> ") while message != 'quit': soc.sendall(message.encode("utf8")) if soc.recv(5120).decode("utf8") == "-": pass # null operation message = input(" -> ") soc.send(b'--quit--') if __name__ == "__main__": main()
Whereas the server program is,
import socket import sys import traceback from threading import Thread def main(): start_server() def start_server(): host = "127.0.0.1" port = 8000 # arbitrary non-privileged port soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print("Socket created") try: soc.bind((host, port)) except: print("Bind failed. Error : " + str(sys.exc_info())) sys.exit() soc.listen(6) # queue up to 6 requests print("Socket now listening") # infinite loop- do not reset for every requests while True: connection, address = soc.accept() ip, port = str(address[0]), str(address[1]) print("Connected with " + ip + ":" + port) try: Thread(target=client_thread, args=(connection, ip, port)).start() except: print("Thread did not start.") traceback.print_exc() soc.close() def clientThread(connection, ip, port, max_buffer_size = 5120): is_active = True while is_active: client_input = receive_input(connection, max_buffer_size) if "--QUIT--" in client_input: print("Client is requesting to quit") connection.close() print("Connection " + ip + ":" + port + " closed") is_active = False else: print("Processed result: <>".format(client_input)) connection.sendall("-".encode("utf8")) def receive_input(connection, max_buffer_size): client_input = connection.recv(max_buffer_size) client_input_size = sys.getsizeof(client_input) if client_input_size > max_buffer_size: print("The input size is greater than expected <>".format(client_input_size)) decoded_input = client_input.decode("utf8").rstrip() result = process_input(decoded_input) return result def process_input(input_str): print("Processing the input received from client") return "Hello " + str(input_str).upper() if __name__ == "__main__": main()
On running above script, run the server_thread1.py in the terminal as,
python server_thread1.py Socket created Socket now listening
We will watch the server window and understand the flow. Now open multiple clients terminal, run client thread
python client_thread1.py Enter 'quit' to exit -> Zack ->
In another terminal, run another client program & watch server terminal window too,
python client_thread1.py Enter 'quit' to exit -> Python -> quit
Another terminal, run client thread,
python client_thread1.py Enter 'quit' to exit -> world! -> Anothny ->
And we can see our server window will display output something like,
Socket created Socket now listening Connected with 127.0.0.1:50275 Processing the input received from client Processed result: Hello ZACK Connected with 127.0.0.1:50282 Processing the input received from client Processed result: Hello PYTHON Processing the input received from client Client is requesting to quit Connection 127.0.0.1:50282 closed Connected with 127.0.0.1:50285 Processing the input received from client Processed result: Hello WORLD! Processing the input received from client Processed result: Hello ANOTHNY
So threads provide one of the most common technique to handle multiple socket connection and clients.
I love programming (: That’s all I know
Socket and thread python
Многопоточность позволяет одновременно выполнять несколько различных действий в различных потоках. Применение многопточности в серверном приложении позволяет обрабатывать одновременно несколько клиентов. Рассмотрим, как создать многпоточное клиент-серверное приложение.
В Python многопоточность обеспечивается функциональностью модулей _thread и threading . В частности, для запуска нового потока мы можем использовать функцию start_new_thread() из модуля _thread , которая имеет следующее определение:
_thread.start_new_thread(function, args[, kwargs])
Эта функция запускает поток, который выполняет функцию из первого параметра function , передавая ей в качестве аргументов кортеж args . Опционально можно передать словарь дополнительных параметров через третий параметр kwargs
Например, определим в файле server.py следующий код сервера
import socket from _thread import * # функция для обработки каждого клиента def client_thread (con): data = con.recv(1024) # получаем данные от клиента message = data.decode() # преобразуем байты в строку print(f"Client sent: ") message = message[::-1] # инвертируем строку con.send(message.encode()) # отправляем сообщение клиенту con.close() # закрываем подключение server = socket.socket() # создаем объект сокета сервера hostname = socket.gethostname() # получаем имя хоста локальной машины port = 12345 # устанавливаем порт сервера server.bind((hostname, port)) # привязываем сокет сервера к хосту и порту server.listen(5) # начинаем прослушиваение входящих подключений print("Server running") while True: client, _ = server.accept() # принимаем клиента start_new_thread(client_thread, (client, )) # запускаем поток клиента
Здесь при подключении каждого нового подключения функция start_new_thread() запускает для его обработки функцию client_thread() и передает ей текущего клиента, который хранится в переменной client. В функции client_thread() для примера получаем от клиента строку, инвертируем ее и отправляем обратно клиенту.
Для тестирования сервера определим следующий код клиента:
import socket client = socket.socket() # создаем сокет клиента hostname = socket.gethostname() # получаем хост локальной машины port = 12345 # устанавливаем порт сервера client.connect((hostname, port)) # подключаемся к серверу message = input("Input a text: ") # вводим сообщение client.send(message.encode()) # отправляем сообщение серверу data = client.recv(1024) # получаем данные с сервера print("Server sent: ", data.decode()) client.close() # закрываем подключение
Клиент ожидает ввод с консоли строки, которая отправляется серверу. Ответ сервера выводится на консоль.
Запустим сервер, затем запустим клиент. Пример работы. Сервер:
c:\python>python server.py Server running Client sent: hello
c:\python>python client.py Input a text: hello Server sent: olleh c:\python>