Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Close listening socket in python thread

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?

like image 377
Norling Avatar asked May 24 '13 12:05

Norling


2 Answers

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...

like image 139
Norling Avatar answered Oct 01 '22 21:10

Norling


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()
like image 25
Eddie Avatar answered Oct 01 '22 23:10

Eddie