关于Python网络编程的设计问题
我现在正在用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 个回答
“我都不知道使用 LineReceiver
处理这种问题是不是个好主意,因为它如果没有收到客户端的数据,就无法发送任何数据。它只有一个 lineReceived
事件。”
你可以在任何地方使用 protocol.transport.write
来发送数据,不仅仅是在 lineReceived
里面。
“我需要一种方法从服务器向客户端发送命令。”
别这么做。这会颠倒“客户端”和“服务器”的正常角色。客户端应该主动发送请求或者获取服务器的数据。
Twisted(或者更一般的事件驱动框架)能解决这个问题吗?
不应该。你在颠倒客户端和服务器的角色。
如果服务器决定发送数据,它应该能够发送;
其实这是错的。
服务器应该等着客户端来请求数据。这是“客户端”和“服务器”的一般定义。
“一个是发送命令给客户端,另一个是把结果传回服务器。这个解决方案听起来更像标准的客户端-服务器通信吗?”
不。
如果客户端向服务器发送消息并接收服务器的响应,这才更符合常见的定义。
有时候,这种情况被描述为有“代理”,每个代理都是一种服务器,还有一个“控制器”,它是所有这些服务器的单一客户端。
控制器负责把工作分配给代理。代理是服务器——它们在一个端口上监听,接受来自控制器的工作,并执行这些工作。每个代理必须同时做两件事(通常通过 select
API):
监控一个固定的套接字,以便接收来自唯一客户端的工作。
在后台执行工作。
这就是客户端-服务器通常的意思。
如果每个代理都是服务器,你会发现很多库都支持这种方式。这是大家都在用的方法。