在python中从外部套接字对象发送数据
我创建了一个在python中从外部套接字对象发送数据,python,sockets,asynchronous,stack,Python,Sockets,Asynchronous,Stack,我创建了一个Clientsocket对象,我实例化了它,它保持了与服务器的连接,工作正常,但我想知道是否有方法从实例外部调用socket.send事件。我准备为消息创建一个堆栈,并检查while循环中的堆栈,如果它不是空的,则将最旧的数据发送到服务器,这对我来说很好,但我的问题是堆栈仅在while循环之后更新(我尝试中断,然后更新)。 所以我的问题是,有没有一种方法可以在运行while循环的同时更新全局堆栈?或者是否有其他方法调用套接字。在对象外部发送事件 import socket impor
Client
socket对象,我实例化了它,它保持了与服务器的连接,工作正常,但我想知道是否有方法从实例外部调用socket.send
事件。我准备为消息创建一个堆栈,并检查while循环中的堆栈,如果它不是空的,则将最旧的数据发送到服务器,这对我来说很好,但我的问题是堆栈仅在while循环之后更新(我尝试中断,然后更新)。
所以我的问题是,有没有一种方法可以在运行while循环的同时更新全局堆栈?或者是否有其他方法调用套接字。在对象外部发送事件
import socket
import sys
import select
import threading
SERVER_IP = '192.168.1.4'
PORT = 8686
TIMEOUT = 5
BUF_SIZE = 1024
MESSAGES = ['testdata1', 'testdata2']
class Client(threading.Thread):
def __init__(self, host=SERVER_IP, port=PORT):
threading.Thread.__init__(self)
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock = socket.create_connection((host, port), 1)
self.sock.setblocking(0)
while 1:
try:
global MESSAGES
ready = select.select([self.sock], [], [], TIMEOUT*1000)
if ready[0]:
buf = self.sock.recv(BUF_SIZE)
print buf
#TODO:do stuff with buf
print 'messages left:'+str(len(MESSAGES))
if len(MESSAGES)>0:
self.sock.send(MESSAGES.pop())
except KeyboardInterrupt:
self.sock.close()
sys.exit(1)
except Exception, e:
print '\n[ERR] %s' % e
self.sock.close()
sys.exit(1)
def run(self):
pass
def sendData(self, data):
global MESSAGES
print 'appending data:%s' % data
MESSAGES.append(data)
def main():
client = Client()
client.start()
client.sendData("test1")
client.sendData("test2")
client.sendData("test3")
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
sys.exit(1)
如果将循环从
__init__() into run()
方法
您的线程不是这样的线程,进程块位于client=client(…)
为什么要混合选择和线程?这真的有必要吗?如果您想要无线程的异步发送和接收,请使用asyncore模块。
或者从代码中删除select。socket.recv()将一直阻塞,直到它以阻塞模式接收数据为止,但由于这是一个线程,我看不出有任何错误。如果在非阻塞模式下,如果没有要接收的数据(如果我记得正确),recv()将只返回None。所以你真的不需要选择。只需检查recv()是否返回None。如果是的话,在再试之前先睡一会儿
您这样做的方式两次困扰您的操作系统。一次用于读取套接字,第二次用于获取套接字的状态,其中timeout用于模拟sleep()而不是其他任何东西。然后循环再次检查,在超时后立即进行select()系统调用,确认该套接字无需执行任何操作。如果将循环从
__init__() into run()
方法
您的线程不是这样的线程,进程块位于client=client(…)
为什么要混合选择和线程?这真的有必要吗?如果您想要无线程的异步发送和接收,请使用asyncore模块。
或者从代码中删除select。socket.recv()将一直阻塞,直到它以阻塞模式接收数据为止,但由于这是一个线程,我看不出有任何错误。如果在非阻塞模式下,如果没有要接收的数据(如果我记得正确),recv()将只返回None。所以你真的不需要选择。只需检查recv()是否返回None。如果是的话,在再试之前先睡一会儿
您这样做的方式两次困扰您的操作系统。一次用于读取套接字,第二次用于获取套接字的状态,其中timeout用于模拟sleep()而不是其他任何东西。然后,循环再次检查,在超时后立即进行select()系统调用,确认该套接字无需执行任何操作。客户端。初始化()不会返回,因为它进入无限while循环。因此,控制永远不会返回到主线程,客户机
线程实际上没有启动
相反,您应该将while循环移动到run()
方法中。然后\uuuu init\uuuu()
方法将控制权返回主线程,然后主线程可以启动线程,并请求客户端通过sendData()
发送消息
您可能不应该使用全局消息列表
来创建主线程和工作线程之间的通信,尤其是在多个工作线程正在运行的情况下。类似这样(未经测试!):
Client.\uuuu init\uuuuu()
不会返回,因为它进入无限while循环。因此,控制永远不会返回到主线程,客户机
线程实际上没有启动
相反,您应该将while循环移动到run()
方法中。然后\uuuu init\uuuu()
方法将控制权返回主线程,然后主线程可以启动线程,并请求客户端通过sendData()
发送消息
您可能不应该使用全局消息列表
来创建主线程和工作线程之间的通信,尤其是在多个工作线程正在运行的情况下。类似这样(未经测试!):
由于您的答案包含了与我相同的信息,但您添加了一些代码,请考虑在没有选择的情况下添加代码,正如我所建议的。否则我会把它加到我的答案里。或者,使用Queue()表示速度对于加快速度没有太大意义。我认为这是一个小型客户端应用程序,所以这些数据类型之间的差异不会有多大影响。但是用不必要的系统调用来干扰操作系统会增加CPU的使用。@Dalen:我的回答中包含了一些与你的相同的信息,但我的回答进一步提出了在主线程和(可能)多个工作线程之间进行通信的线程安全方式。这是一个更好的体系结构,当然比使用全局变量要好。关于速度,问题是什么?OP没有提到一个,而且Queue
并不慢。@Dalen:关于线程中select()
的使用,正如你所说的,并不理想。在本例中,最好只执行阻塞recv()
,尽管不难想象主线程可能希望向工作线程发送消息以控制它,例如quit命令。在这种情况下,使用select()
并不是不合理的,因此我将保留我的答案。我同意,但正如我所解释的,这不是客户机速度的问题。它只会使一个系统调用超出需要。select()很快,是的,但是为什么要先用syscall来打扰操作系统,然后select()自己反复检查套接字5秒钟呢。如果超时时间更小,select()对套接字的影响更小,但对操作系统的影响更大。至于线程安全,首先,我建议OP尽可能不要将消息存储在全局变量中
import Queue
class Client(threading.Thread):
def __init__(self, msg_queue, host=SERVER_IP, port=PORT):
threading.Thread.__init__(self)
self.msg_queue = msg_queue
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock = socket.create_connection((host, port), 1)
self.sock.setblocking(0)
def run(self):
while 1:
try:
ready = select.select([self.sock], [], [], TIMEOUT*1000)
if ready[0]:
buf = self.sock.recv(BUF_SIZE)
print buf
#TODO:do stuff with buf
print 'messages left:'+ str(self.msg_queue.qsize())
try:
msg = self.msg_queue.get_nowait()
self.sock.send(msg)
except Queue.Empty:
pass
except KeyboardInterrupt:
self.sock.close()
sys.exit(1)
except Exception, e:
print '\n[ERR] %s' % e
self.sock.close()
sys.exit(1)
def main():
# create a queue and pass it to the client
msg_queue = Queue.Queue()
client = Client(msg_queue)
client.start()
msg_queue.put("test1")
msg_queue.put("test2")
msg_queue.put("test3")