I am trying to write a code in python, using multithreading, that runs UDP server side and UDP client side in a single program file. I need to make sure that the threads are synchronized.
The problem (as far as i have understood) with my code is that when thread1 runs, it acquires the lock since thread1's run() method runs the serverSide() method which contains a forever while loop, thread1 does not release the lock and therefore, the program gets stuck.
Can anyone please help me synchronize the threads while making sure the server and client run properly
import threading
import time
import sys
from datetime import datetime
from socket import *
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
# Get lock to synchronize threads
threadLock.acquire()
serverSide()
# Free lock to release next thread
threadLock.release()
class myThread1 (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
# Get lock to synchronize threads
threadLock.acquire()
clientSide()
# Free lock to release next thread
threadLock.release()
def serverSide():
serverPort = 44000
serverIP = '192.168.0.0'
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind((serverIP,serverPort))
print ("SERVER HERE!\nThe server is ready to receive")
while 1:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.upper()
serverSocket.sendto(modifiedMessage, clientAddress)
def clientSide():
serverIP = "192.168.0.0"
serverPort = 44000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = raw_input("CLIENT HERE!\nInput lowercase sentence:")
clientSocket.sendto(message.encode(),(serverIP, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage) # print the received message
clientSocket.close() # Close the socket
threadLock = threading.Lock()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread1(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
# Add threads to thread list
threads.append(thread1)
threads.append(thread2)
# Wait for all threads to complete
for t in threads:
t.join()
print "Exiting Main Thread"
Your code works fine except the synchronisation part.
So the issue is this, There is one threadLock = threading.Lock() which once acquired by either of the two threads the other thread wont be able to acquire.
Once a thread has acquired it, It wont release it till its job is done. It's job cant be done unless the other thread is up and running. The other thread is waiting for the 1st thread to release lock.
You have artificially manage to induce a race condition in your code which is not at all required. I simply removed the entire part with thread lock and its working fine. Except that i had to interrupt the program to end it.
import threading
import time
import sys
from datetime import datetime
from socket import *
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("Starting " + self.name)
# Get lock to synchronize threads
# threadLock.acquire()
serverSide()
# Free lock to release next thread
# threadLock.release()
class myThread1 (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print ("Starting " + self.name)
# Get lock to synchronize threads
# threadLock.acquire()
clientSide()
# Free lock to release next thread
# threadLock.release()
def serverSide():
serverPort = 44000
serverIP = '127.0.0.1'
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind((serverIP,serverPort))
print ("SERVER HERE!\nThe server is ready to receive")
while 1:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.upper()
serverSocket.sendto(modifiedMessage, clientAddress)
def clientSide():
serverIP = "127.0.0.1"
serverPort = 44000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input("CLIENT HERE!\nInput lowercase sentence:")
clientSocket.sendto(message.encode(),(serverIP, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print("received", modifiedMessage) # print the received message
clientSocket.close() # Close the socket
# threadLock = threading.Lock()
threads = []
# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread1(2, "Thread-2", 2)
# Start new Threads
thread1.start()
thread2.start()
# Add threads to thread list
threads.append(thread1)
threads.append(thread2)
# Wait for all threads to complete
for t in threads:
t.join()
print ("Exiting Main Thread")
output:
Starting Thread-1
Starting Thread-2
SERVER HERE!
The server is ready to receive
CLIENT HERE!
Input lowercase sentence:viki
received b'VIKI'
NOTE:
i am trying to write a code in python, using multithreading, that runs UDP server side and UDP client side in a single program file. i need to make sure that the threads are synchronized.
A client server architecture is in most cases not supposed to be synchronized. Google server and my browser are not synchronized. And they are not supposed to be same applies for your code. Reason for that being that a server should run independent of wether a client is running or not.
A client should run independent of wether a server is up or not. Client request will fail if the server is down. But still it should run.
Related
I want to implement a streaming server which sends and endless stream of data to all connected clients. Multiple clients should be able to connect and disconnect from the server in order to process the data in different ways.
Each client is served by a dedicated ClientThread, which sub-classes Thread and contains a queue of the data to be sent to the client (necessary, since clients might process data at different speeds and because bursts of data can occur which the clients might be unable to handle).
The program listens to incoming client connections via a seperate ClientHandlerThread. Whenever a client connects, the ClientHandlerThread spawns a ClientThread and adds it to a list.
As a dummy example, the main Thread increments an integer each second and pushes it to all ClientThread queues through ClientHandlerThread.push_item().
Every 10 increments, the number of items in the client queues is printed.
Now to my questions:
When a client disconnects, the Thread terminates and no more data is send, however, the ClientThread object remains in the ClientHandlerThreads list of clients and items are continuously pushed to its queue.
I'm therefore looking for either (1) a way to delete the ClientThread object from the list whenever a client disconnects, (2) a better way to monitor the ClientThreads than a list or (3) a different (better) architecture to archive my goal.
Many thanks!
Server
import socket
import time
from threading import Thread
from queue import Queue
class ClientThread(Thread):
def __init__(self, conn, client_addr):
Thread.__init__(self)
self.queue = Queue()
self.conn = conn
self.client_addr = client_addr
def run(self):
print('Client connected')
while True:
try:
self.conn.sendall(self.queue.get().encode('utf-8'))
time.sleep(1)
except BrokenPipeError:
print('Client disconnected')
break
class ClientHandlerThread(Thread):
def __init__(self):
Thread.__init__(self, daemon = True)
self.clients = list()
def push_item(self, item):
for client in self.clients:
client.queue.put(str(i))
def run(self):
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.bind('./socket')
s.listen()
i = 1
while True:
conn, client_addr = s.accept()
client = ClientThread(conn, client_addr)
client.start()
self.clients.append(client)
i += 1
if __name__ == '__main__':
client_handler = ClientHandlerThread()
client_handler.start()
i = 1
while True:
client_handler.push_item(str(i))
if i % 10 == 0:
print('[' + ', '.join([str(client.queue.qsize()) for client in client_handler.clients]) + ']')
i += 1
time.sleep(1)
Client:
import socket
if __name__ == '__main__':
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.connect('./socket')
print('Connected to server')
while True:
data = s.recv(1024)
if not data:
print('Disconnected from server')
break
print(data.decode('utf-8'))
Note You should probably read up on things like aiohttp for much more scalable versions to your answer.
For your question, you can make a few changes to achieve this:
First, change ClientThread's constructor:
class ClientThread(Thread):
def __init__(self, client_handler, conn, client_addr):
self.client_handler = client_handler
self.running = True
...
When the handler creates the object, it should pass self to it as client_handler.
In the run method, use
def run(self):
while True:
...
self.running = False
self.client_handler.purge()
That is, it marks itself as not running, and calls the purge method of handler. This can be written as
class ClientHandlerThread(Thread):
...
def purge(self):
self.clients = [c for c in self.clients if c.running]
I have the following server program in Python which simulates a chat-room. The code accepts connections from clients and for each of them it launches a new thread. This thread will wait for messages from this client. The messages can be L so that the server will respond with a list of connected clients, ip:port msg the server will send the message msg to the client ip:port.
On client side there will be 2 threads, one for receiving messages from the server, the other for sending.
import socket
from threading import Thread
#from SocketServer import ThreadingMixIn
import signal
import sys
import errno
EXIT = False
address = []
address2 = []
# handler per il comando Ctrl+C
def sig_handler(signum, frame):
if (signum == 2):
print("Called SIGINT")
EXIT = True
signal.signal(signal.SIGINT, sig_handler) # setto l'handler per i segnali
# Multithreaded Python server : TCP Server Socket Thread Pool
class ClientThread(Thread):
def __init__(self,conn,ip,port):
Thread.__init__(self)
self.conn = conn
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + ip + ":" + str(port))
def run(self):
while True:
data = self.conn.recv(1024)
print ("Server received data:", data)
if (data=='L'):
#print "QUI",address2
tosend = ""
for i in address2:
tosend = tosend + "ip:"+str(i[0]) + "port:"+str(i[1])+"\n"
self.conn.send(tosend)
#mandare elenco client connessi
else:
#manda ip:port msg
st = data.split(" ")
msg = st[1:]
msg = ' '.join(msg)
print ("MSG 2 SEND: ",msg)
ipport = st[0].split(":")
ip = ipport[0]
port = ipport[1]
flag = False
print ("Address2:",address2)
print ("ip:",ip)
print ("port:",port)
for i in address2:
print (i[0],ip,type(i[0]),type(ip),i[1],type(i[1]),port,type(port))
if str(i[0])==str(ip) and str(i[1])==str(port):
i[2].send(msg)
self.conn.send("msg inviato")
flag = True
break
if flag == False:
self.conn.send("client non esistente")
if __name__ == '__main__':
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '127.0.0.1'
TCP_PORT = 2004
TCP_PORTB = 2005
BUFFER_SIZE = 1024 # 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))
tcpServerB = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServerB.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServerB.bind((TCP_IP, TCP_PORTB))
threads = []
tcpServer.listen(4)
tcpServerB.listen(4)
while True:
print("Multithreaded Python server : Waiting for connections from TCP clients...")
try:
(conn, (ip,port)) = tcpServer.accept()
except socket.error as e: #(code, msg):
if e.errno != errno.EINTR:
raise
else:
break
address.append((ip,port,conn))
(conn2, (ip2,port2)) = tcpServerB.accept()
address2.append((ip2,port2,conn2))
newthread = ClientThread(conn,ip,port)
newthread.start()
threads.append(newthread)
if EXIT==True:
break
print ("SERVER EXIT")
for t in threads:
t.join()
The code has a signal handler for SIGINT to make the exit cleaner (closing connections, sending a message to the client (still to be implemented) and so on ). The handler writes a global flag EXIT to make the infinite loops terminate.
The code runs both in Python2 and Python3. However there are some problems with SIGINT signal generated by CTRL-C. When there is no client connected the program launched with Python2 exits correctly while the one in Python3 does not. Why this behavioural difference?
Considering only running the program in Python2, when a client connects and I press CTRL-C, the main while exits, like the signal is catched always by the main thread and this interrupts the blocking system call accept. However the other threads do not, I think because of the blocking underlying system call data = self.conn.recv(1024). In C I would block SIGINT signals for one thread and then call pthread_cancel from the other thread. How to exit from all threads when SIGINT is generated in Python?
The client program that for the moment works in Python2 only and suffers from the same problem is:
# Python TCP Client A
import socket
from threading import Thread
class ClientThread(Thread):
def __init__(self,conn):
Thread.__init__(self)
self.conn = conn
def run(self):
while True:
data = self.conn.recv(1024)
print "Ricevuto msg:",data
host = socket.gethostname()
print "host:",host
port = 2004
portB = 2005
BUFFER_SIZE = 2000
tcpClientA = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientB = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpClientA.connect(('127.0.0.1', port))
tcpClientB.connect(('127.0.0.1', portB))
newthread = ClientThread(tcpClientB)
newthread.start()
while(True):
msg = raw_input("Inserisci comando: ")
tcpClientA.send (msg)
data = tcpClientA.recv(BUFFER_SIZE)
print "data received:",data
tcpClientA.close()
As for the difference in behavior with accept() in Python 3, look at the full description in the docs. I think this is the key statement:
Changed in version 3.5: If the system call is interrupted and the signal handler does not raise an exception, the method now retries the system call instead of raising an InterruptedError exception (see PEP 475 for the rationale).
The other problem, stated in your penultimate sentence:
How to exit from all threads when SIGINT is generated in Python 2?
Take a look at the threading documentation:
A thread can be flagged as a “daemon thread”. The significance of this flag is that the entire Python program exits when only daemon threads are left. The initial value is inherited from the creating thread. The flag can be set through the daemon property.
I have a server with main process acepting socket connections and put them in Queue stack and another process monitoring this stack and applying it to pool processes handling connections. All works fine except for one thing:
last connection allways at stuck until another connection appears, it's look like last connection can't be closed, but why?
from multiprocessing import Queue, Process, Pool, Manager
import datetime
import socket
def get_date():
return datetime.datetime.now().strftime('%H:%M:%S')
class Server:
def __init__(self, host, port):
self.server_address = host, port
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def run(self):
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind(self.server_address)
self.server_socket.listen(1)
print('listen at: %s:%s' % self.server_address)
q = Manager().Queue()
Process(target=self.handle_request, args=(q,)).start()
while True:
client_socket, adress = self.server_socket.accept()
print('\n[%s] request from: %s:%s' % (get_date(), *adress))
q.put(client_socket)
client_socket.close()
del client_socket # client_socket.close() not working
def help(self, client_socket):
data = client_socket.recv(512)
client_socket.send(data)
client_socket.close()
print(data[:50])
def handle_request(self, q):
with Pool(processes=2) as pool:
while True:
pool.apply_async(self.help, (q.get(),))
Server('localhost', 8000).run()
close doesn't realy close connection unless no other process holding a reference, but shutdown will affect all processes. you could call client_socket.shutdown(socket.SHUT_WR) before client_socket.close().
Update:
the reason close doesn't fully close connection is there is a process started by Manager() is holding a reference. Use Queue instead would make close works as you expected.
I would better start the question from the code.
from multiprocessing import Process, Event, Queue
from threading import Timer
from Queue import Empty
class MyServer(Process):
def __init__(self, port, queue):
Process.__init__(self)
self.port = port
self.queue = queue
self.sd = None
def run(self):
try:
self.start_serving()
except KeyboardInterrupt:
print("Shutting down..")
finally:
if self.sd is not None:
self.sd.close()
def start_serving(self):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sd = s
try:
s.bind(('', self.port))
s.listen(1)
while True:
conn, addr = s.accept()
while True:
# I dont want to bore you with excess code
# just recv data from clients
try:
msg = self.queue.get_nowait()
# here i start Timer with delay from message (I'll describe Message class below)
Timer(msg.delay, self.response_handler, args=(conn, msg)).start()
except Empty:
pass
conn.close()
finally:
s.close()
def response_handler(self, sd, msg):
# doesn't matter
# and now I want to terminate the MyServer instance
if msg.terminate:
# the problem is here. Lets call it 'problem line'
sys.exit()
msg is instance of Message class which is:
class Message(object):
def __init__(self, port, delay, values, terminate=False):
self.port = port
self.delay = delay
self.values = values
self.terminate = terminate
The logic is I get data from clients via TCP connection and check Queue for message. Messages are things to control the server. Sometimes I get a message like "wait 3 seconds and terminate the server".
What I have done so far.
Call self.terminate() at the problem line. I get
AttributeError: 'NoneType' object has no attribute 'terminate'
Raise an exception at the problem line. I assumed the exception was caught in run() function. I was
wrong
Call sys.exit(). It doesn't work too.
Perhaps my question can be shorter. How to terminate the process from its thread in Python?
Why don't you use multiprocessing.Event (you are already importing it) and exit the process gracefully if you get an terminate message.
To do this add this to __init__:
self.exit = Event()
And change the two while loops:
while True:
conn, addr = s.accept()
while True:
#...
to
while not self.exit.is_set():
conn, addr = s.accept()
while not self.exit.is_set()
#...
then in your response handler:
if msg.terminate:
self.exit.set()
this will allow the code to naturally exit the loops, ensuring that conn.close() is called.
So I'm learning about socket programming and have wrote a nifty little chat server. The problem I am having is that my client cannot read and write at the same time. I'm not too sure how to set this up.
This is what I have so far, I want read() and write() to be running concurrently (It isn't so much about reading and writing at the same time - it's about being able to receive messages while input() hangs waiting for user input.):
import socket
import threading
class Client(threading.Thread):
def __init__(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(('127.0.0.1', 1234))
print('Client connected to server')
self.readThread = threading.Thread.__init__(self)
self.writeThread = threading.Thread.__init__(self)
def read(self):
data = self.socket.recv(1024)
if data:
print('Received:', data)
def write(self):
message = input()
self.socket.send(bytes(message, 'utf-8'))
client = Client()
while True:
#do both
You're really close. Try something like this:
import socket
import threading
class Client(threading.Thread):
def __init__(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect(('127.0.0.1', 1234))
print('Client connected to server')
t = threading.Thread(target = self.read)
t.daemon = True # helpful if you want it to die automatically
t.start()
t2 = threading.thread(target = self.write)
t2.daemon = True
t2.start()
def read(self):
while True:
data = self.socket.recv(1024)
if data:
print('Received:', data)
def write(self):
while True:
message = input()
self.socket.send(bytes(message, 'utf-8'))
client = Client()
It's worth pointing out that if you're reading and writing from a single terminal this way your prompt could get a little out of hand. I imagine though that you're starting with print statements, but will eventually collect data into other containers in your app.