14

我在尝试了解用于网络通信的套接字时遇到问题。我制作了一个简单的线程来监听连接并为连接客户端创建进程,但我的问题是我无法让线程正确加入,因为我还没有找到取消 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(不管实际超时,即使我将它设置为年......)。

我究竟做错了什么?我是否以愚蠢的方式设计了线程,或者我错过了一些关于接受连接的事情?

4

5 回答 5

16

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

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

这行得通,但它仍然感觉它可能不是最佳的......

于 2013-05-24T13:32:28.377 回答
1

在大多数情况下,一旦连接被接受,您将打开一个新线程或进程。要关闭连接,请中断 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()
于 2013-10-23T10:35:58.957 回答
1

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

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

请注意,sys.exit当它试图干净地退出/释放资源时,它不起作用/阻塞。但这os._exit是最低级别的方式,它可以工作,当没有其他方法时。

操作系统本身会像exit在 C 程序中那样释放资源(在任何现代系统上)。

于 2018-04-13T14:33:40.743 回答
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 秒超时等待。您可以自己连接到它。

于 2020-06-08T03:14:38.460 回答
-1

部分测试解决方案

  1. 放在self.socket.settimeout(0.1)前面while
  2. 紧随conn.settimeout(None)其后accept
于 2014-08-03T04:56:10.027 回答