Python 网络客户端,尝试响应服务器响应
该应用程序是一个 WxPython 客户端/服务器设置,有多个客户端连接到服务器并参与双工网络协议。
我过去曾将 Twisted 与 AMP 联系在一起,但它并没有完全适应应用程序中的架构,最终也没有使事情变得过于复杂。
因此,对于服务器,我已经设置了 ThreadingMixIn 的 SocketServer 。目前我正在研究服务器的缓冲区/命令队列,但这不是问题。
在客户端,我可以执行由 UI 中的事件触发的所有正常数据发送,没有太多问题。我目前正试图让客户端监听响应而不阻塞整个应用程序。所以我想把它放在一个线程中,但它应该从现在注释掉的部分开始,还是应该以完全不同的方式处理,而我只是没有看到它?
简而言之:我希望客户端向服务器发送命令并侦听任何响应,而不会阻止/停止整个应用程序。
下面的代码是原型代码,请原谅任何典型的错误,例如魔法值和其他硬编码数据,它在最终代码中会有所不同。
import socket
import threading
import time
class CommandProxy(object):
def __init__(self, host, port):
self.host = host
self.port = port
def close(self):
if self.connection:
self.connection.close()
def connect(self):
try:
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connection.connect((self.host, self.port))
except socket.error as e:
print "Socket error: {0}".format(e)
def send_command(self, command, *kw):
datalist = ' '.join(kw)
data = command + ' ' + datalist + '\x00'
print 'DATA: {0}'.format(data)
self._write(data)
# while True:
# data = self._read()
# if data == 0:
# break
#
# print "DATA RECEIVED: {0}".format(data)
def _read(self):
data = self.connection.recv(1024)
return data
def _write(self, bytes):
self.connection.sendall(bytes)
if __name__ == '__main__':
HOST, PORT = 'localhost', 1060
proxy = CommandProxy(HOST, PORT)
proxy.connect()
try:
while True:
proxy.send_command('ID', '1')
time.sleep(2)
except KeyboardInterrupt:
print "Interrupted by user"
except socket.error as e:
print "Socket error: {0}".format(e)
except Exception as e:
print "something went wrong: {0}".format(e)
finally:
proxy.close()
The application is a WxPython client/server setup that has multiple clients connect to the server and engaging in duplex networking protocol.
I've had Twisted hooked up with AMP in the past, but it did not fully cut it for the architecture in the application without overly complicating things in the end.
So for the server I have got SocketServer with the ThreadingMixIn set up. At the moment I am working on the buffer/command queue for the server, but that's not the issue.
On the client side I can do all the normal sending of data, triggered by events in the UI, without too much problems. I am currently stuck trying to get the client to listen for responses without blocking the entire application. So I want to put this in a thread, but should it start at the part that's now commented out or should it be handled completely different and I am just not seeing it?
In short: I want the client to send commands to the server and listen for any responses without blocking/stalling the entire application.
The code below is prototyping code, please excuse any typical mistakes such as magical values and other hardcoded data, it will be different in the final code.
import socket
import threading
import time
class CommandProxy(object):
def __init__(self, host, port):
self.host = host
self.port = port
def close(self):
if self.connection:
self.connection.close()
def connect(self):
try:
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connection.connect((self.host, self.port))
except socket.error as e:
print "Socket error: {0}".format(e)
def send_command(self, command, *kw):
datalist = ' '.join(kw)
data = command + ' ' + datalist + '\x00'
print 'DATA: {0}'.format(data)
self._write(data)
# while True:
# data = self._read()
# if data == 0:
# break
#
# print "DATA RECEIVED: {0}".format(data)
def _read(self):
data = self.connection.recv(1024)
return data
def _write(self, bytes):
self.connection.sendall(bytes)
if __name__ == '__main__':
HOST, PORT = 'localhost', 1060
proxy = CommandProxy(HOST, PORT)
proxy.connect()
try:
while True:
proxy.send_command('ID', '1')
time.sleep(2)
except KeyboardInterrupt:
print "Interrupted by user"
except socket.error as e:
print "Socket error: {0}".format(e)
except Exception as e:
print "something went wrong: {0}".format(e)
finally:
proxy.close()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为您错误地认为单线程或多线程方法是否会使您的应用程序或多或少变得复杂。您现在正在努力解决的问题是(例如)Twisted 为您开箱即用解决的众多问题之一。
人们对 Twisted 最常见的抱怨是,它使他们以一种他们不习惯的方式奇怪地构建代码。然而,当您使用像 wxPython 这样的 GUI 库时,您已经接受了这个约束。 Twisted 的事件驱动架构与所有流行 GUI 工具包的事件驱动架构完全相同。只要您继续使用 wxPython,使用 Twisted 就不会强迫您做任何您不想做的事情。
另一方面,切换到线程意味着您需要非常小心地访问共享数据结构,您将无法有效地进行单元测试,并且只有当其他人运行您的应用程序时才会出现许多问题- 因为他们的核心数量与您不同,或者他们的网络具有不同的延迟特征,或者任何其他导致您的线程代码以您从未经历过的方式运行的因素。只要极其小心,你仍然可以写出有用的东西,但会困难得多。
由于您尚未在此发布任何基于 Twisted 的代码,因此我无法就如何使事情尽可能简单给出任何具体建议。但是,我建议您再考虑一下非线程解决方案。加入[email protected]邮件列表,跳上#twisted在 freenode 上,或发布更多有关它的 stackoverflow 问题。很多人都会热心提供帮助。 :)
I think you're mistaken about whether a single-threaded or multi-threaded approach will complicate your application more or less. The problem you're wrestling with now is one of the many that (for example) Twisted solves for you out of the box.
The most common complaint people have about Twisted is that it makes them structure their code strangely, in a way they're not used to. However, when you're using a GUI library like wxPython, you have already accepted this constraint. Twisted's event-driven architecture is exactly like the event-driven architecture of all the popular GUI toolkits. As long as you keep using wxPython, also using Twisted isn't going to force you to do anything else you don't want to do.
On the other hand, switching to threads will mean you need to be very careful about access to shared data structures, you won't be able to unit test effectively, and many problems that arise will only do so when someone else is running your application - because they have a different number of cores than you, or their network has different latency characteristics, or any of a number of other things which cause your threaded code to run in ways you never experienced. With extreme care you can still write something that works, but it will be much more difficult.
Since you haven't posted any of your Twisted-based code here, I can't really give any specific advice on how to keep things as simple as possible. However, I recommend that you take another look at a non-threaded solution. Join the [email protected] mailing list, hop on #twisted on freenode, or post more stackoverflow questions about it. Lots of people will be eager to help. :)
IMO 你有权使用线程。为每个请求启动一个线程,当它完成并有数据时,生成一个 wx 事件(请参阅 http://wiki .wxpython.org/CustomEventClasses)
IMO your right with using a thread. Start a thread for every request, and when it's done and have a data, generate a wx event (see http://wiki.wxpython.org/CustomEventClasses)