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
Related
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 am struggling to get my python socket to behave.
There are two major problems:
1) When it listens for the client connection the program stalls which is a problem because it is running on a IRC client python interpreter causing the IRC client not to respond until the client connects.
2) When the client disconnects the entire script has to be stopped and then restarted again inorder to get the socket server to listen once more.
I thought the way around it might be to start the socket listening in a separate thread, so the IRC client can continue while it waits for the client connection. Also, once the client has decided to close the connection I need a way restart it.
The following code is terrible and doesn't work but it might give you an idea as to what I'm attempting:
__module_name__ = "Forward Module"
__module_version__ = "1.0.0"
__module_description__ = "Forward To Flash Module by Xcom"
# Echo client program
import socket
import sys
import xchat
import thread
import time
HOST = None # Symbolic name meaning all available interfaces
PORT = 7001 # Arbitrary non-privileged port
s = None
socketIsOpen = False
def openSocket():
# start server
print "starting to listen"
for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC,
socket.SOCK_STREAM, 0, socket.AI_PASSIVE):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except socket.error as msg:
s = None
continue
try:
s.bind(sa)
s.listen(1)
except socket.error as msg:
s.close()
s = None
continue
break
if s is None:
print 'could not open socket'
global socketIsOpen = False
sys.exit(1)
conn, addr = s.accept()
print 'Connected by', addr
global socketIsOpen = True
def someone_said(word, word_eol, userdata):
username = str(word[0])
message = str(word[1])
sendMessage = username + " : " + message
send_to_server(sendMessage)
def send_to_server(message):
conn.send(message)
def close_connection():
conn.close()
print "connection closed"
xchat.hook_print('Channel Message' , someone_said)
def threadMethod(arg) :
while 1:
if (not socketIsOpen) :
openSocket()
try:
thread.start_new_thread(threadMethod, args = [])
except:
print "Error: unable to start thread"
The python is running on an IRC client called HexChat which is where the xchat import comes from.
The way you usually program a threaded socket server is:
call accept() in a loop
spawn a new thread to handle the new connection
A very minimal example would be somethig like this:
import socket
import threading
import time
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 9999))
server.listen(1)
def handle(conn):
conn.send(b'hello')
time.sleep(1) # do some "heavy" work
conn.close()
while True:
print('listening...')
conn, addr = server.accept()
print('handling connection from %s' % (addr,))
threading.Thread(target=handle, args=(conn,)).start()
You're spawning new threads in which you create your listening socket, then accept and handle your connection. And while socketIsOpen is True your programm will be using a lot of cpu looping through your while loop doing nothing. (btw, the way you check socketIsOpen allows for race conditions, you can start multiple threads before it is set.)
And one last thing, you should try to use the threading module instead of the deprecated thread.
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()
I'm having a little trouble with sockets in Python. Whenever someone connects it works fine but if they disconnect the server program closes. I want the server program to remain open after the client closes. I'm using a while True loop to keep the connection alive but once the client closes the connection the server closes it's connection.
Here is the client:
import socket, sys
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1]
port = int(sys.argv[2])
conn.connect((host, port))
print("Connected to host " + sys.argv[1])
td = 1
while td == 1:
msg = raw_input('MSG: ')
Here is the server:
import socket, sys
socket.setdefaulttimeout(150)
host = ''
port = 50005
socksize = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("Server started on port: %s" % port)
s.listen(1)
print("Now listening...\n")
conn, addr = s.accept()
while True:
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
If a client closes a connection, you want it to close the socket.
It seems like there's a bit of a disconnect here that I'll try to elaborate on. When you create a socket, bind, and listen, you've established an open door for others to come and make connections to you.
Once a client connects to you, and you use the accept() call to accept the connection and get a new socket (conn), which is returned for you to interact with the client. Your original listening socket is still there and active, and you can still use it to accept more new connections.
Looking at your code, you probably want to do something like this:
while True:
print("Now listening...\n")
conn, addr = s.accept()
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
Please note that this is just a starting point, and as others have suggested you probably want to use select() along with forking off processes or spawning threads to service each client.
Your code is only accepting a single connection - the loop only deals with the first accepted connection and terminates as soon as it lost. This is way your server exists:
data = conn.recv(socksize)
if not data:
break
What you will need to do is to accept several connections, while handling each of those in it's own loop. Note that it does not have to be a real loop for each socket, you can use a select-based approach to query which of the sockets has an event associated with it (data available, connection lost etc.) and then process only those sockets, all in the same loop.
You can also use a multi threaded / multi process approach, dealing with each client in it's own thread or process - I guess you won't run into scaling issues when playing around.
See:
http://docs.python.org/library/select.html
http://docs.python.org/library/multiprocessing.html
I have a main thread that waits for connection. It spawns client threads that will echo the response from the client (telnet in this case). But say that I want to close down all sockets and all threads after some time, like after 1 connection.
How would I do it? If I do clientSocket.close() from the main thread, it won't stop doing the recv. It will only stop if I first send something through telnet, then it will fail doing further sends and recvs.
My code looks like this:
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocket):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
# It will hang here, even if I do close on the socket
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
time.sleep(1)
# This won't make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
I know this is an old thread and that Samuel probably fixed his issue a long time ago. However, I had the same problem and came across this post while google'ing. Found a solution and think it is worthwhile to add.
You can use the shutdown method on the socket class. It can prevent further sends, receives or both.
socket.shutdown(socket.SHUT_WR)
The above prevents future sends, as an example.
See Python docs for more info.
I don't know if it's possible to do what you're asking, but it shouldn't be necessary. Just don't read from the socket if there is nothing to read; use select.select to check the socket for data.
change:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
to something more like this:
r, _, _ = select.select([self.clientSocket], [], [])
if r:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
EDIT: If you want to guard against the possibility that the socket has been closed, catch socket.error.
do_read = False
try:
r, _, _ = select.select([self.clientSocket], [], [])
do_read = bool(r)
except socket.error:
pass
if do_read:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
I found a solution using timeouts. That will interrupt the recv (actually before the timeout has expired which is nice):
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocke):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except socket.timeout:
# If it was a timeout, we want to continue with recv
continue
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
clientSocket.settimeout(1)
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
# Close it down immediatly
clientSocket.close()
I must apologize for the comments below. The earlier comment by #Matt Anderson works. I had made a mistake when trying it out which led to my post below.
Using timeout is not a very good solution. It may seem that waking up for an instant and then going back to sleep is no big deal, but I have seen it greatly affect the performance of an application. You have an operation that for the most part wants to block until data is available and thus sleep forever. However, if you want to abort for some reason, like shutting down your application, then the trick is how to get out. For sockets, you can use select and listen on two sockets. Your primary one, and a special shutdown one. Creating the shutdown one though is a bit of a pain. You have to create it. You have to get the listening socket to accept it. You have to keep track of both ends of this pipe. I have the same issue with the Synchronized Queue class. There however, you can at least insert a dummy object into the queue to wake up the get(). This requires that the dummy object not look like your normal data though. I sometimes wish Python had something like the Windows API WaitForMultipleObjects.