如何在Python中将TCP服务器放到另一个线程上

3 投票
2 回答
7922 浏览
提问于 2025-04-17 05:41

我想用Python写一个守护进程,但我不知道怎么用线程来启动一个并行的TCP服务器。而且我也不确定应该用哪种类型的服务器:asyncore、SocketServer还是socket?

这是我代码的一部分:

import os
def demonized():
   child_pid = os.fork()
   if child_pid == 0:
       child_pid = os.fork()
       if child_pid == 0:          #fork twice for demonize
           file = open('###', "r") # open file
           event = file.read()
           while event:
               #TODO check for changes put changes in list variable
               event = file.read()
       file.close()
       else:
           sys.exit(0)
   else:
       sys.exit(0)


if __name__ == "__main__":
  demonized()

在一个循环中,我有一个列表变量,每次循环都会添加一些数据。我想在这个循环中启动一个线程,让TCP服务器等待连接。如果有客户端连接,就把这些数据发送给它(同时清空变量)。所以我不需要处理多个客户端,因为一次只会有一个客户端连接。实现这个的最佳方法是什么?

谢谢。

2 个回答

-1

你想在 while event:... 循环中往列表里添加东西,同时又想使用这个列表吗?如果是这样的话,你就有两个写入者,这样的话你需要想办法保护你的列表。

在这个例子中,使用了 SocketServer.TCPServerthreading.Lock

import threading
import SocketServer
import time


class DataHandler(SocketServer.StreamRequestHandler):

    def handle(self):
        self.server.list_block.acquire()
        self.wfile.write(', '.join(self.server.data))
        self.wfile.flush()
        self.server.data = []
        self.server.list_block.release()


if __name__ == '__main__':
    data = []
    list_block = threading.Lock()

    server = SocketServer.TCPServer(('localhost', 0), DataHandler)
    server.list_block = list_block
    server.data = data

    t = threading.Thread(target=server.serve_forever)
    t.start()

    while True:
        list_block.acquire()
        data.append(1)
        list_block.release()
        time.sleep(1)
8

如果你想避免重复写一些常规的代码,Python很快会有一个标准模块,可以处理fork()和标准输入输出的操作(你还没把这些加到你的程序里吗?),这样就能让你的程序变成一个守护进程。你现在就可以从以下链接下载并使用这个模块:

http://pypi.python.org/pypi/python-daemon

在一个单独的线程中运行TCP服务器通常很简单:

import threading

def my_tcp_server():
    sock = socket.socket(...)
    sock.bind(...)
    sock.listen()
    while True:
        conn, address = sock.accept()
        ...
        ... talk on the connection ...
        ...
        conn.close()

def main():
    ...
    threading.Thread(target=my_tcp_server).start()
    ...

我强烈建议你不要尝试让你的文件读取线程和处理socket的线程通过自己设计的列表和锁来进行交流;这样的方案很难实现,也很难维护。相反,建议使用标准库中的Queue.Queue()类,它会为你正确处理所有的锁定和添加操作。

撰写回答