关于Python网络编程的设计问题

3 投票
2 回答
835 浏览
提问于 2025-04-16 04:28

我现在正在用Python写一个项目,这个项目有客户端和服务器端。我在网络通信方面遇到了一些麻烦,所以需要解释一下情况……

客户端主要是按照服务器的指示进行操作,然后把操作结果发送回服务器。我需要一种方法,让它们之间可以双向通信,使用TCP套接字。

目前的情况

我现在在服务器端使用的是Twisted框架的LineReceiver,而在客户端则是用普通的Python socket(还有ssl),因为我没能正确实现Twisted的PushProducer。客户端有一个Queue,里面存放着要发送给服务器的数据;一个子进程会不断从队列中取数据并发送给服务器(见下面的代码)。

在这种情况下,如果客户端只是把结果推送给管理者,那是可以正常工作的。但服务器无法向客户端发送数据。更准确地说,客户端无法接收到服务器发送的数据。

问题所在

我需要一种方法,从服务器向客户端发送命令。

我考虑在客户端的循环中监听传入的数据,这个循环是用来从队列发送数据的:

def run(self):
    while True:
        data = self.queue.get()
        logger.debug("Sending: %s", repr(data))
        data = cPickle.dumps(data)
        self.socket.write(data + "\r\n")
        # Here would be a good place to listen on the socket

但是这个解决方案有几个问题:

  • SSLSocket.read()方法是一个阻塞方法
  • 如果队列中没有数据,客户端就永远收不到任何数据

是的,我可以用Queue.get_nowait()代替Queue.get(),但总的来说,我觉得这不是个好解决方案。

我的疑问

有没有好的方法用Twisted来实现这些需求? 我对Twisted的了解不多,找不到合适的解决办法。我甚至不知道使用LineReceiver是否适合这个问题,因为如果没有从客户端接收到数据,它就无法发送任何数据。它只有一个lineReceived事件。

Twisted(或者更一般的说,任何事件驱动的框架)能解决这个问题吗? 我在通信方面甚至没有真正的事件。如果服务器决定发送数据,它应该能够发送;在通信方面不应该需要等待任何事件。

2 个回答

2

“我都不知道使用 LineReceiver 处理这种问题是不是个好主意,因为它如果没有收到客户端的数据,就无法发送任何数据。它只有一个 lineReceived 事件。”

你可以在任何地方使用 protocol.transport.write 来发送数据,不仅仅是在 lineReceived 里面。

-1

“我需要一种方法从服务器向客户端发送命令。”

别这么做。这会颠倒“客户端”和“服务器”的正常角色。客户端应该主动发送请求或者获取服务器的数据。

Twisted(或者更一般的事件驱动框架)能解决这个问题吗?

不应该。你在颠倒客户端和服务器的角色。

如果服务器决定发送数据,它应该能够发送;

其实这是错的。

服务器应该等着客户端来请求数据。这是“客户端”和“服务器”的一般定义。


“一个是发送命令给客户端,另一个是把结果传回服务器。这个解决方案听起来更像标准的客户端-服务器通信吗?”

不。

如果客户端向服务器发送消息并接收服务器的响应,这才更符合常见的定义。

有时候,这种情况被描述为有“代理”,每个代理都是一种服务器,还有一个“控制器”,它是所有这些服务器的单一客户端。

控制器负责把工作分配给代理。代理是服务器——它们在一个端口上监听,接受来自控制器的工作,并执行这些工作。每个代理必须同时做两件事(通常通过 select API):

  • 监控一个固定的套接字,以便接收来自唯一客户端的工作。

  • 在后台执行工作。

这就是客户端-服务器通常的意思。

如果每个代理都是服务器,你会发现很多库都支持这种方式。这是大家都在用的方法。

撰写回答