I was just messing around with threading in python, wrote this basic IM thingy [code at bottom]
I noticed that when I kill the program with C-c it doesn't exit, it just hangs forever.
I'm just guessing it's waiting for each thread to finish what they are doing, but since it's an endless loop that will never happen.
So I guess I need to kill each thread manually, or end the loop when the killsignal comes in.
How would I do that?
#!/usr/bin/env python
import threading
import socket
class Listen(threading.Thread):
def run(self):
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.bind(('', 2727))
conn.listen(1)
while True:
channel, details = conn.accept()
print str(details)+": "+channel.recv(250)
channel.send("got it")
channel.close()
class Shout(threading.Thread):
def run(self):
while True:
try:
address = raw_input("who u talking to? ")
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((address, 2727))
break
except:
print "can't connect to "+ str(address)
while True:
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((address, 2727))
conn.send(raw_input())
conn.close()
listen = Listen().start()
shout = Shout().start()
I see several causes of the misbehavior in your code.
Ctrl+C causes a "KeyboardInterrupt" exception in the main thread. So you should handle it there.
Your socket is in blocking mode. This causes several socket functions to block the calling thread until the function returns. During this state the thread cannot react to any termination event.
As you already said: your endless loop in the thread's run() function is ... really endless. So the thread execution is never ending (at least not without an unexpected exception). You should use some kind of synchronization object, like an threading.Event object, to be able to tell a thread externally that it should terminate itself.
I would discourage the use of raw_input() out of the main thread. Imagine what happens when you have more than one Shout thread.
Why are you always closing and reconnecting the socket when a message has been transmitted in your Shout class? Network connections should be re-established only in special cases because of the setup costs.
Without a frame protocol for the communication you can never expect to have received all data that was sent by the other host when the recv() function returns.
The start() function of the thread object does not return a value or object. So saving the returned value (=None) doesn't make much sense.
You can never expect the send() function to transmit all passed data. Therefore you must check the result of the function and appropriately handle the situation when not all bytes were really transmitted.
To learn threading there are surely better problems to solve than network communication, since that topic is in itself really complex.
Beside all these things, here is my try for a solution. Still there is much that can be improved. You should consider the answer from Mark Tolonen too, since the SocketServer class is surely provided to ease several things in handling this kind of stuff. But you should keep on studying the basics too.
#!/usr/bin/env python
import threading
import socket
import time
import errno
class StoppableThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.stop_event = threading.Event()
def stop(self):
if self.isAlive() == True:
# set event to signal thread to terminate
self.stop_event.set()
# block calling thread until thread really has terminated
self.join()
class Accept(StoppableThread):
def __init__(self, port):
StoppableThread.__init__(self)
self.port = port
self.threads = []
def run(self):
# handle connection acception
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.bind(('', self.port ))
conn.listen(5)
# set socket timeout to ~10ms
conn.settimeout(0.01)
while self.stop_event.is_set() == False:
try:
csock, caddr = conn.accept()
# spawn a new thread to handle the client connection
listen_thread = Listen(csock, caddr)
self.threads.append(listen_thread)
listen_thread.start()
except socket.timeout:
# socket operation timeout
# clear all terminated threads from thread list
for thread in self.threads:
if thread.isAlive() == False:
self.threads.remove(thread)
self.stop_threads()
def stop_threads(self):
# stop all running threads
for listen_thread in self.threads:
if listen_thread.isAlive() == True:
listen_thread.stop()
self.threads = []
class Listen(StoppableThread):
def __init__(self, csock, caddr):
StoppableThread.__init__(self)
self.csock = csock
self.caddr = caddr
self.csock.setblocking(False)
def run(self):
while self.stop_event.is_set() == False:
try:
recv_data = self.csock.recv(250)
if len(recv_data) > 0:
print str(self.caddr)+": " + recv_data
self.csock.send("got it")
else:
# connection was closed by foreign host
self.stop_event.set()
except socket.error as (sock_errno, sock_errstr):
if (sock_errno == errno.EWOULDBLOCK):
# socket would block - sleep sometime
time.sleep(0.1)
else:
# unexpected / unhandled error - terminate thread
self.stop_event.set()
channel.close()
class Shout(StoppableThread):
def __init__(self, sport):
StoppableThread.__init__(self)
self.sport = sport
def run(self):
while self.stop_event.is_set() == False:
try:
address = raw_input("who u talking to? ")
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect((address, self.sport))
break
except socket.error:
# handle connection problems
print "can't connect to "+ str(address)
except:
# exit thread in case of an unexpected error
self.stop_event.set()
while self.stop_event.is_set() == False:
try:
# chat loop: send messages to remote host
print "what to send? :",
msg = raw_input()
# beware: send() function may block indefinitly here and it might not send all bytes as expected !!
conn.send(msg)
except:
# exit thread in case of an unexpected error
self.stop_event.set()
# close socket before thread terminates
conn.close()
def main():
do_exit = False
server_port = 2727
# start server socket thread
accept = Accept(server_port)
accept.start()
# start transmitting client socket thread
shout = Shout(server_port)
shout.start()
while do_exit == False:
try:
# sleep some time
time.sleep(0.1)
except KeyboardInterrupt:
# Ctrl+C was hit - exit program
do_exit = True
# stop all running threads
shout.stop()
accept.stop()
# exit main program after all threads were terminated gracefully
if __name__ == "__main__":
main()
Look at the Python library source for SocketServer.py, in particular the implementation of server_forever() to see how a server implements a quit. It uses select() to poll the server socket for new connections and tests a quit flag. Here's a hack on your source to use SocketServer, and I added a quit flag to Shout(). It will run the Shout and Listen threads for 5 seconds and then stop them.
import socket
import SocketServer
import threading
import time
class Handler(SocketServer.StreamRequestHandler):
def handle(self):
print str(self.client_address) + ": " + self.request.recv(250)
self.request.send("got it\n")
class Listen(threading.Thread):
def run(self):
self.server = SocketServer.TCPServer(('',2727),Handler)
self.server.serve_forever()
def stop(self):
self.server.shutdown()
class Shout(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.quit = False
def run(self):
while not self.quit:
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
conn.connect(('localhost', 2727))
conn.send('sending\n')
print conn.recv(100)
conn.close()
def stop(self):
self.quit = True
listen = Listen()
listen.start()
shout = Shout()
shout.start()
time.sleep(5)
shout.stop()
listen.stop()
Related
I have an application which runs multiple servers all on their own threads. I want to be able to tell a thread to stop running. To do this though I would need to tell the thread to stop, the thread would then need to tell the server to stop and the server would then close its own socket (which is in a receiving loop, getting data from all the connected clients). How would I do this?
I have tried using passed stop variables, however I think the issue is in the socket needing to be closed. I can't find a way to tell the server to close the socket without sending a direct message to the server telling it to do so, which seems inefficient.
Here is my server code:
import socket
import threading
class Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connections = []
def __init__(self, port):
self.sock.bind(('0.0.0.0', port))
self.sock.listen(1)
def handler(self, c, a):
while True:
try:
data = c.recv(1024) #loop won't run until recieved dat
except:
c.shutdown(socket.SHUT_RDWR)
c.close()
break
print("Chat: ", str(data, 'utf-8'))
if not data:
c.close()
break
def run(self):
self._stop = False
while not self._stop:
c, a = self.sock.accept() ##c is client and a is address
cThread = threading.Thread(target=self.handler, args=(c,a))
cThread.daemon = True
cThread.start()
self.connections.append(c)
print("Server: ", str(a[0]) + ':' + str(a[1]), "connected")
self.close()
def shutdownServer(self):
self._stop = True
def close(self):
print('Closing server')
if self.sock:
self.sock.close()
self.sock = None
def serverRun(port, stop):
while True:
print("server port: " + str(port))
actual_server = Server(port)
actual_server.run()
if(stop):
print("Stopping server thread")
break
Here is the code which sets up the thread and runs the server:
def main():
stopThreads = False
thread = threading.Thread(target = server.serverRun, args=(1, lambda : stopThreads,))
thread.start()
time.sleep(1)
stopThreads = True
thread.join()
print("server thread killed")
main()
Any help would be appreciated.
Edit: Edited to clarify the problem is less so closing the thread and more so passing a variable to the class being run in the thread, so it can close its socket when the thread is trying to be stopped.
Okay, so I figured out the blocker was the socket.accept() function. So for anyone who may have the same issue with terminating server threads, you can just use a sock.select() before your sock.accept() to check if there are any incoming connections. If you use a sock.select() and add a timeout to it, the whole loop will run after the allotted time it waits for connections, so the thread can be killed if the event has told it to do so and if it hasn't, it will look for connections again.
You can use the thread event function (which stovfl mentioned in comments on the main thread) to tell the thread when to stop.
Here is how I changed my code so it can now self terminate:
def run(self, running):
while running.is_set():
timeout = 2
readable, writable, errored = select.select([self.sock], [], [], timeout)
for s in readable:
if s is self.sock:
client_socket, a = self.sock.accept() ##c is client and a is address
cThread = threading.Thread(target=self.handler, args=(client_socket, a))
cThread.daemon = True
cThread.start()
self.connections.append(client_socket)
print("Server: ", str(a[0]) + ':' + str(a[1]), "connected")
self.close()
def serverRun(running, port):
while running.is_set():
print("server port: " + str(port))
actual_server = Server(port)
actual_server.run(running)
And main was changed to:
def main():
running = threading.Event()
running.set()
thread = threading.Thread(target=server.serverRun, args=(running, 1))
thread.start()
time.sleep(30)
print("Event running.clear()")
running.clear()
print('Wait until Thread is terminating')
thread.join()
print("EXIT __main__")
main()
I am using a windows 7 machine with Python 2.7 to make a simple Client/Server ZMQ proof of concept. I ran into this scenario where the listening socket(Server side of the app) is already in use and this throws "zmq.error.ZMQError: Address in use" error. How do you think is the best way to avoid this error? I was thinking of, when binding the socket catch this error and if error is thrown restart the context and the socket. This is not working, is still throws and error when binding. Server code:
class ZMQServer:
context = None
socket = None
def __init__(self, port):
self.context = zmq.Context()
self.socket = self.context.socket(zmq.REP)
try:
self.socket.bind("tcp://*:"+str(port))
except zmq.error.ZMQError:
print ("socket already in use, restarting")
self.socket.close()
self.context.destroy()
self.context = zmq.Context()
self.socket = self.context.socket(zmq.REP)
self.socket.bind("tcp://*:"+str(port))
I tried another approach, instead of checking the availability of the socket, I am trying to manage it correclty, to do this:
Created the listener async, on a separate thread.
Created a method that will close the socket at exit
In the socket binding I only catch the ZMQError and display it, I didn;t find a way to fix the blocked socked there.
The recv method that receives the messages is NON-blocking
So, the code now looks like this:
"
import time
import zmq
import threading
class ZMQServer:
context = None
socket = None
alive = False
ZMQthread = None
def __init__(self, port):
self.context = zmq.Context()
self.socket = self.context.socket(zmq.REP)
try:
self.socket.bind("tcp://*:"+str(port))
except zmq.error.ZMQError:
print ("socket already in use, try restarting it")
self.alive = False
self.alive = True
def StartAsync(self):
self.alive = True
ZMQthread = threading.Thread(target=self.Start)
ZMQthread.start()
def Start(self):
while self.alive == True:
# Wait for next request from client
print("Wait for next request from client")
try:
message = self.socket.recv(zmq.NOBLOCK)
print("Received request: %s" % message)
# Do some 'work'
time.sleep(1)
# Send reply back to client
self.socket.send(b"World")
except:
print "no message received in time. trying again"
def CloseServer(self):
print("Stoping the server")
self.alive = False
if(self.socket.closed == False):
self.socket.close()
if self.ZMQthread and self.ZMQthread.is_alive() == True:
self.ZMQthread.join()
if __name__ == '__main__':
zmqServer = ZMQServer(5555)
zmqServer.StartAsync()
time.sleep(20)
zmqServer.CloseServer()
I'm trying to run new process for each new instance of class Server. Each Server instance should listen on specific port. I have this (simplified) code so far: source
class Server(object):
def handle(connection, address):
print("OK...connected...")
try:
while True:
data = connection.recv(1024)
if data == "":
break
connection.sendall(data)
except Exception as e:
print(e)
finally:
connection.close()
def __init__(self, port, ip):
self.port = port
self.ip = ip
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.bind((self.ip, self.port))
self.socket.listen(1)
while True:
print("Listening...")
conn, address = self.socket.accept()
process = multiprocessing.Process(target=Pmu.handle, args=(conn, address))
process.daemon = True
process.start()
s1 = Server(9001,"127.0.0.1")
s2 = Server(9002,"127.0.0.1")
But when I run this script only first server s1 is running and waiting for connection. How to make both servers listening at the same time?
Your current server is effectively a SocketServer.ForkingTCPServer that enters a tight loop in its __init__, foerever accepting new connections, and creating a new child process for each incoming connection.
The problem is that __init__ never returns, so only one server gets instantiated, one socket gets bound, and only one port will accept new requests.
A common way of solving this type of problem is to move the accept loop into a worker thread. This code would look something like this:
import multiprocessing
import threading
import socket
class Server(object):
def handle(self, connection, address):
print("OK...connected...")
try:
while True:
data = connection.recv(1024)
if data == "":
break
connection.sendall(data)
except Exception as e:
print(e)
finally:
connection.close()
print("Connection closed")
def accept_forever(self):
while True:
# Accept a connection on the bound socket and fork a child process
# to handle it.
print("Waiting for connection...")
conn, address = self.socket.accept()
process = multiprocessing.Process(
target=self.handle, args=(conn, address))
process.daemon = True
process.start()
# Close the connection fd in the parent, since the child process
# has its own reference.
conn.close()
def __init__(self, port, ip):
self.port = port
self.ip = ip
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((self.ip, self.port))
self.socket.listen(1)
# Spin up an acceptor thread
self.worker = threading.Thread(target=self.accept_forever)
self.worker.daemon = True
self.worker.start()
def join(self):
# threading.Thread.join() is not interruptible, so tight loop
# in a sleep-based join
while self.worker.is_alive():
self.worker.join(0.5)
# Create two servers that run in the background
s1 = Server(9001,"127.0.0.1")
s2 = Server(9002,"127.0.0.1")
# Wait for servers to shutdown
s1.join()
s2.join()
Note one other change I snuck in here:
# Wait for servers to shutdown
s1.join()
s2.join()
Using the saved reference to the Server's accept worker, we call .join() from the main thread to force things to block while the servers are running. Without this, your main program will exit nearly immediately, due to the workers' .daemon attribute being set.
It's also worth noting that this approach will have some quirks:
Since the handler functions are running in separate processes, you will need to share data structures between them carefully using Queue, Value, Pipe, and other multiprocessing constructs if they depend on each other.
There is no rate limiting of active concurrent connections; creating a new process for every single request can be expensive, and can create a vector for your service being easily DoSed.
I'm writing a simple TCP socket server with pyBonjour support. To do this I figured using threading. The problem is how I get the server to stop... I figured the following should work (according to this) but it isn't
Is there a nicer way to do this (that works)..
import SocketServer
import threading
import pybonjour
import select
import time
class BonjourThread(threading.Thread):
def run(self):
sdRef = pybonjour.DNSServiceRegister(name = 'MacroServer - Mac',
regtype = '_macroserver._tcp',
port = 12000,
callBack = self.bonjour_register_callback)
while True:
ready = select.select([sdRef], [], [])
if sdRef in ready[0]:
pybonjour.DNSServiceProcessResult(sdRef)
def bonjour_register_callback(self, sdRef, flags, errorCode, name, regtype, domain):
if errorCode == pybonjour.kDNSServiceErr_NoError:
print 'Bonjour started'
class TCPThread(threading.Thread):
def run(self):
try:
HOST, PORT = "localhost", 12000
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
print 'TCP server started'
server.serve_forever()
except KeyboardInterrupt:
print 'Closing Down'
exit()
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
try:
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
# just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
except KeyboardInterrupt:
print 'Closing Down'
exit()
if __name__ == "__main__":
try:
thread1 = TCPThread()
thread1.start()
thread2 = BonjourThread()
thread2.start()
while True: time.sleep(100)
except (KeyboardInterrupt, SystemExit):
print 'Received keyboard interrupt, quitting threads.\n'
finally:
print 'And its bye from me'
In python, only the main thread gets the KeyboardInterrupt signal. How you want to handle termination of your socket servers and their various clients can get complex. I've made logging servers where I kept the sockets in a master list, protected by a lock, and closed them all then waited for termination in the keyboard interrupt. You could even mark the threads as daemons and just exit - let the operating system clean up the sockets.
from place you linked to:
thread.daemon=True causes the thread to terminate when the main process ends.
which you missed in your code, so that's why they don't stop
as to nicer ways to do it, you could create your own signal handler and terminate your threads but not sure if it's any nicer than:
thread.daemon=True
I have a problem trying to learn about sockets for network communication. I have made a simple thread that listens for connections and creates processes for connecting clients, my problem though is that I can't get the thread to join properly as I haven't found a way to cancel the socket.accept()-call when I want to quit the program.
My code looks like this;
class ServerThread( threading.Thread ):
def __init__(self, queue, host, port):
threading.Thread.__init__(self)
self.queue = queue
self.running = True
self.hostname = host
self.port = port
def run(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((self.hostname, self.port))
self.socket.listen(1)
while self.running:
try:
conn, address = self.socket.accept()
process = Process(target=server_slave, args=(conn, address, self.queue))
process.daemon = True
process.start()
except socket.timeout:
pass
def stop(self):
self.running = False
self.socket.close()
I have managed to get the program to close by setting self.setDaemon(True) and just exiting the main program, handing everything to the great garbage collector - but that seems like a bad solution. I've also tried setting a timeout for the socket but that results in getting [Errno 35] Resource temporarily unavailable (regardless of the actual timeout, even when I set it to years...).
What am I doing wrong? Have I designed the thread in a dumb way or have I missed something about accepting connections?
One way to get the thread to close seems to be to make a connection to the socket, thus continuing the thread to completion.
def stop(self):
self.running = False
socket.socket(socket.AF_INET,
socket.SOCK_STREAM).connect( (self.hostname, self.port))
self.socket.close()
This works, but it still feels like it might not be optimal...
In most cases you will open a new thread or process once a connection is accepted. To close the connection, break the while loop. Garbage collection will remove the thread or process but join will ensure none get left behind.
Persistent sockets close when the user closes them or they timeout. Non-persistent, like static webpages will close after they've sent the information.
Here's a good example of a persistent socket server in Python. It uses multiprocessing which means it can run across multiple cores for CPU-bound tasks. More commonly known as multithreading.
import socket
import multiprocessing
def run():
host = '000.000.000.000'
port = 1212
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', port))
sock.listen(3)
while True:
p = multiprocessing.Process(target=worker, args=sock.accept()).start()
def worker(conn, addr):
while True:
if data == '':
#remote connection closed
break
if len(dataList) > 2:
# do stuff
print 'This code is untested'
run()
A dirty solution which allows to exit your program is to use os._exit(0).
def stop(self):
self.socket.close()
os._exit(0)
note that sys.exit doesn't work/blocks as it tries to exit cleanly/release resources. But os._exit is the most low level way and it works, when nothing else does.
The operating system itself will release the resources (on any modern system) like when doing exit in a C program.
The best way to do this is to have a single listening thread that has nothing to do with your connection threads and give it a reasonable length timeout. On timeout, check if this thread should shutdown and if not, loop again and go back to listening.
def tcp_listen_handle(self, port=23, connects=5, timeout=2):
"""This is running in its own thread."""
sock = socket.socket()
sock.settimeout(timeout)
sock.bind(('', port))
sock.listen(connects) # We accept more than one connection.
while self.keep_running_the_listening_thread():
connection = None
addr = None
try:
connection, addr = sock.accept()
print("Socket Connected: %s" % str(addr))
# makes a thread deals with that stuff. We only do listening.
self.handle_tcp_connection_in_another_thread(connection, addr)
except socket.timeout:
pass
except OSError:
# Some other error.
print("Socket was killed: %s" % str(addr))
if connection is not None:
connection.close()
sock.close()
The only thing this does is listen, timeout, checks if it should die during the timeout, and goes back to listening. The general rule of thumb is that threads should check whether they should die and try to do that themselves as fast as they can. And if you don't want to take the 2 second hit for timeout wait before the thread unblocks and checks. You can connect to it yourself.
Partially tested solution
Put self.socket.settimeout(0.1) right before while
Put conn.settimeout(None) right after accept