Exiting thread in a python multithreaded server - python

I'm trying to make a multithreaded server in python right now that sends a header line and then the html file requested but I've run into a bit of a snag. I'm pretty sure my threads aren't exiting when the function is done. My server is printing "ready to serve..." more times than it should (and encountering random errors from time to time). I heard that if a thread hits a handled exception it might not exit, but it appears not to exit even when things run smoothly without exception.
I'm pretty new to python and am used to making these in C where I can simply exit threads from within the thread but my research has told me it's not quite that simple in python. Any help on how to fix or improve the server would be amazing!
#import socket module
from socket import *
import threading
def work(connectionSocket):
try:
message = connectionSocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
#Send one HTTP header line into socket
connectionSocket.send("Header Line")
#Send the content of the requested file to the client
for i in range(0, len(outputdata)):
connectionSocket.send(outputdata[i])
connectionSocket.close()
except IOError:
#Send response message for file not found
connectionSocket.send("404 File Not Found.")
connectionSocket.close()
return
def server():
threads = []
serverPort = 14009
serverSocket = socket(AF_INET, SOCK_STREAM)
#Prepare a sever socket
serverSocket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
while True:
#Establish the connection
print 'Ready to serve...'
connectionSocket, addr = serverSocket.accept()
t = threading.Thread(target=work, args=(connectionSocket,))
threads.append(t)
t.start()
serverSocket.close()
if __name__ == '__main__':
server()

The reason it prints out 'Ready to server' more than once is that you put print 'Ready to serve...' in the loop. If you only want it to print once, just put it outside the loop.
And to make sure that every thread exits, it's a better practice to join all the threads when the program ends. Then the code would be like this:
print('Ready to serve...')
while True:
#Establish the connection
try:
connectionSocket, addr = serverSocket.accept()
except KeyboardInterrupt:
break
t = threading.Thread(target=work, args=(connectionSocket,))
threads.append(t)
t.start()
print("Exiting")
for t in threads:
t.join(5)
serverSocket.close()

Related

Python socket: Errno 9 Bad file descriptor when recv

My problem is like this. I would need to create a client program for quick trial that can send out some commands and listen to data(after which I would need to parse it) from the same socket. So I have created two threads(one to issue command (not shown here), the other to listen to data) to handle this after I created the sockets and connect out to the server. Server is written in other langauges.
As the same socket is to be used, I thought that the socket should be set to be unblocking
the socket after creation is send to the thread as an arguement.
I tried to run the python program. And there is a problem of OSError: [Errno 9] Bad file descriptor. I have narrowed down the problem. It got to do with the recv function.
Most of the solution down in the forum seem to point to socket closure as the main problem but i really could not see how since the socket closure was placed out of while loop.
So need somebody help to point to the problem. And here is my code (as below)
import socket
import errno
import sys
import threading
HOST = "192.168.50.35"
PORT = 2356
def listener(sock, q):
print("status thread created")
while q != True:
try:
data = sock.recv(1024)
except socket.error as socketerr:
if socketerr == errno.EAGAIN or socketerr == errno.EWOULDBLOCK:
sleep(1)
print('Data is unavailable')
continue
else:
print(socketerr)
sys.exit(1)
else:
print(f" new {data!r} recieved")
### processed data
### some processing set but not shown here
continue
sock.close()
def connect():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.connect((HOST, PORT))
s.setblocking(0)
s.settimeout(1)
except socket.error as socketerr:
print("Error: ", socketerr)
return s
if __name__ == '__main__':
print_machine_info()
q = False
s = connect()
print("socket created")
t1 = threading.Thread(target=status, args=(s,q))
t1.daemon = False
t1.start()

Socket python doesn't send data if program is alive

I'm trying to run a client/server script, where the client sends a file to the server and waits for responses until the server sends a stop message.
The problem is: once the connection is established the client starts sending data but until I press CTRL-C the server cannot recreate the file. Only after CTRL-C print "file is fully created" and the file becomes visible, instead, before it's seems to be waiting for something. idk where the problem is. Also tried changing condition on send loop using len(), but doesn't work. Anyone know how to fix it ?
client.py :
import socket # Import socket module
# from threading import Thread
s = socket.socket() # Create a socket object
HOST = "101.xx.x.xxx" # public IP address
PORT = 4243 # Reserve a port for your service.
PDF_PATH = "exam.pdf"
s.connect((HOST, PORT))
def send():
f = open(PDF_PATH, "rb")
while data := f.read(4096):
s.send(data)
f.close()
return
def receive():
while 1:
exercise = s.recv(4096)
if exercise == "stop!":
s.close()
break
f = open(f"{exercise}.txt", "wb")
while data := f.read(4096):
f.write(data)
return
def main():
send()
receive()
if __name__ == "__main__":
main()
server.py :
import socket
from threading import Thread
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
HOST = socket.gethostname()
IP = socket.gethostbyname(HOST)
PORT = 4243
s.bind(('', PORT))
s.listen(5)
def receive_file(conn, i):
f = open(f"exam.pdf", "wb")
while received := conn.recv(4096):
f.write(received)
print("File is fully copied\n")
f.close()
def send_result(conn,i):
while 1:
nbr = str(input("which exercise? "))
if nbr == "stop!":
break
f = open(f"exercise{nbr}.txt", "rb")
conn.send(bytes(f"exercise{nbr}.txt", encoding="utf-8"))
while data := f.read(4096):
conn.send(data)
f.close()
def main():
try:
while 1:
i = 0
conn, addr = s.accept()
print("Got connection from", addr)
# c.send(b"Thank you for connecting")
t = Thread(target=receive_file, args=(conn, i))
t.start()
t.join()
t = Thread(target=send_result, args=(conn, i))
t.start()
t.join()
except KeyboardInterrupt:
print("interrupting \n")
conn.close()
s.close()
if _name_ == '_main_':
main()
conn.recv() in the server won't return '' (no more data) unless the client closes the connection or calls shutdown(SHUT_WR) to indicate sends are complete:
def send():
with open(PDF_PATH, "rb") as f:
while data := f.read(4096):
s.sendall(data)
s.shutdown(socket.SHUT_WR)
An alternative is to design a protocol that sends the length of data before the data so you know when you've received the complete transmission. This would be required if you need to send more than one thing without closing the socket or shutting down sends. You're going to need this to make the receive portion of the server work if you want to send more than one exercise file.
Refer to this answer for an example of sending multiple files over a socket.

chat-room server not closing threads and not exiting when SIGINT

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.

Python Socket Scripting. What am i doing wrong?

My socket program hangs at clientsocket, address) = serversocket.accept() and doesn't spit our an error or anything.
I followed directions on https://docs.python.org/3/howto/sockets.html
I've been trying to figure it out for an hour now, but to no avail. I'm using python3 btw. What am i doing wrong? EDIT: My intedentation is all screwed up because I pasted it wrong, but other than that my code is as I have it in my file.
#import socket module
import socket
#creates an inet streaming socket.
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('socket created')
#binds socket to a public host, and a well known port
serversocket.bind(('127.0.0.1', 1024))
#print(socket.gethostname())# on desktop prints 'myname-PC')
#become a server socket
serversocket.listen(5) # listens for up to 5 requests
while True:
#accept connections from outside
#print('In while true loop') This works, but we never get to the next print statement. Why the hell is it catching at line 20?
(clientsocket, address) = serversocket.accept()
#clientsocket = serversocket.accept()
print('Ready to serve')
#now we do something with client socket...
try:
message = clientsocket.recv(1024)
filename = message.split()[1]
f = open(filename[1:])
outputdata = f.read()
#send an http header line
clientsocket.send('HTTP/1.1 200 OK\nContent-Type: text/html\n\n')
for i in range(0, len(outputdata)):
clientsocket.send(outputdata[i])
clientsocket.close()
except IOERROR:
clientsocket.send('HTTP/1.1 404 File not found!')
clientsocket.close()
If you haven't written a client script / program to connect to the socket and send it data, it's also going to hang on serversocket.accept() due to there being nothing to accept. But assuming you have...
while True:
#accept connections from outside
#print('In while true loop') This works, but we never get to the next print statement. Why the hell is it catching at line 20?
(clientsocket, address) = serversocket.accept()
#clientsocket = serversocket.accept()
It hangs because the loop never exits due to True always being True. In the example provided, once a connection is accepted they pretend that the server is threaded and the idea is to create a separate thread to begin reading and processing data received allowing the socket to continue to listen for more connections.
while True:
# accept connections from outside
(clientsocket, address) = serversocket.accept()
# now do something with the clientsocket
# in this case, we'll pretend this is a threaded server
ct = client_thread(clientsocket)
ct.run()

Python Server send data not working

I am currently working on a server in Python, the problem I am facing is the client could not retrieve the sent data from server.
The code of the server is:
import sys
import socket
from threading import Thread
allClients=[]
class Client(Thread):
def __init__(self,clientSocket):
Thread.__init__(self)
self.sockfd = clientSocket #socket client
self.name = ""
self.nickName = ""
def newClientConnect(self):
allClients.append(self.sockfd)
while True:
while True:
try:
rm= self.sockfd.recv(1024)
print rm
try:
self.sockfd.sendall("\n Test text to check send.")
print "Data send successfull"
break
except socket.error, e:
print "Could not send data"
break
except ValueError:
self.sockfd.send("\n Could not connect properly")
def run(self):
self.newClientConnect()
self.sockfd.close()
while True:
buff = self.sockfd.recv(1024)
if buff.strip() == 'quit':
self.sockfd.close()
break # Exit when break
else:
self.sendAll(buff)
#Main
if __name__ == "__main__":
#Server Connection to socket:
IP = '127.0.0.1'
PORT = 80
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
print ("Server Started")
try:
serversocket.bind(('',5000))
except ValueError,e:
print e
serversocket.listen(5)
while True:
(clientSocket, address) = serversocket.accept()
print 'New connection from ', address
ct = Client(clientSocket)
ct.start()
__all__ = ['allClients','Client']
#--
And the client connecting is:
import socket
HOST = '192.168.1.4' # The remote host
PORT = 5000 # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
data = s.recv(1024)
s.close()
print 'Received', data#repr(data)
In need of a quick solution....
Thanks,
I tested out your code, and when I commented out
rm= self.sockfd.recv(1024)
print rm
it worked fine. Basically the server stopped there to wait for a message that never came. If it still does not work for you, there might be two problems. Either you have a firewall that blocks the connection somehow, or you have old servers running in the background from previous tries that actually wasn't killed. Check your processes if pythonw.exe or equivalent is running when it shouldn't be, and kill it.
To wait for response:
with s.makefile('rb') as f:
data = f.read() # block until the whole response is read
s.close()
There are multiple issues in your code:
nested while True without break
finally: ..close() is executed before except ValueError: ..send
multiple self.sockfd.close()
etc
Also you should probably use .sendall() instead of .send().
your server code is excepting client send something first,
rm= self.sockfd.recv(1024)
but I don't see any in your code
please try send something in your client code
s.connect((HOST, PORT))
s.send("hello")
Short solution
Add a short sleep after connect.
import time
time.sleep(3)

Categories

Resources