在python线程中关闭侦听套接字

时间:2013-05-24 12:04:46

标签: python multithreading sockets

我在尝试了解网络通信套接字时遇到问题。我做了一个简单的线程,它监听连接并创建连接客户端的进程,我的问题是我无法正常连接线程,因为我还没有找到取消socket.accept()的方法 - 调用当我想退出该计划时。

我的代码看起来像这样;

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()

我设法通过设置self.setDaemon(True)并退出主程序,将所有内容交给大垃圾收集器来关闭程序 - 但这似乎是一个糟糕的解决方案。我也尝试为套接字设置超时,但这会导致获得[Errno 35] Resource temporarily unavailable(无论实际超时,即使我将其设置为年......)。

我做错了什么?我是否以愚蠢的方式设计了线程,或者我错过了接受连接的内容?

5 个答案:

答案 0 :(得分:11)

让线程关闭的一种方法似乎是建立与套接字的连接,从而继续完成线程。

def stop(self):
    self.running = False
    socket.socket(socket.AF_INET, 
                  socket.SOCK_STREAM).connect( (self.hostname, self.port))
    self.socket.close()

这样可行,但感觉可能不是最佳......

答案 1 :(得分:1)

允许退出程序的脏解决方案是使用os._exit(0)

def stop(self):
    self.socket.close()
    os._exit(0)

请注意sys.exit在尝试彻底退出/释放资源时不起作用/阻止。但是os._exit是最低级别的方式,它起作用,当没有别的时候。

操作系统本身将释放资源(在任何现代系统上),就像在C程序中执行exit一样。

答案 2 :(得分:0)

在大多数情况下,一旦接受连接,您将打开一个新线程或进程。要关闭连接,请中断while循环。垃圾收集将删除线程或进程,但加入将确保没有留下任何东西。

持久套接字在用户关闭或超时时关闭。非持久性,如静态网页,在发送信息后将关闭。

这是Python中持久套接字服务器的一个很好的例子。它使用多处理,这意味着它可以跨多个核心运行以进行CPU绑定任务。通常称为多线程。

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()

答案 3 :(得分:0)

执行此操作的最佳方法是拥有一个与您的连接线程无关的侦听线程,并为其提供合理的长度超时。超时时,请检查该线程是否应该关闭,否则请再次循环并返回监听。

    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()

唯一要做的就是监听,超时,检查是否应该在超时期间终止并返回监听。一般的经验法则是,线程应该检查是否应该死掉,并尽自己最大的努力做到这一点。而且,如果您不想让2秒命中超时,请等待线程取消阻塞并检查。您可以自己连接它。

答案 4 :(得分:-1)

部分测试的解决方案

  1. self.socket.settimeout(0.1)放在while
  2. 之前
  3. conn.settimeout(None)
  4. 之后立即accept