在 python 中从外部套接字对象发送数据
Sending data from outside socket object in python
我创建了一个 Client
套接字对象,我对其进行实例化并保持与服务器的连接,工作正常,但我想知道是否有一种方法可以调用 socket.send
来自实例外部的事件。我正准备为消息创建一个堆栈并在 while 循环中检查堆栈,如果它不为空,则将最旧的数据发送到服务器,这对我来说很好,但我的问题是堆栈仅在之后更新while 循环(我尝试突破,然后更新)。
所以我的问题是,有没有办法在 while 循环 运行 的同时更新全局堆栈?或者有没有其他方法可以在对象外调用 socket.send
事件?
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()
方法代替。
你的线程不是这样的线程,process blocks at client = Client(...).
为什么要混合 select 和线程?这真的有必要吗?如果你想在没有线程的情况下进行异步发送和接收,请使用 asyncore 模块。
或者从您的代码中删除 select。 socket.recv() 将阻塞,直到它以阻塞模式接收数据,但由于这是一个线程,我看不出有什么不妥。如果在非阻塞模式下,如果我没记错的话,如果没有要接收的数据,recv() 将只是 return None。所以你真的不需要 select。只需检查 recv() returned None。如果是,请先睡一会儿再试。
你这样做的方式让你的 OS 麻烦了两次。一次用于读取套接字,第二次用于获取套接字的状态,其中超时用于模拟 sleep() 比其他任何事情都重要。然后循环再次检查在超时后立即进行 select() 系统调用,确认该套接字无事可做。
Client.__init__()
不会 return 因为它进入了无限循环。因此,控制永远不会 return 到主线程,并且 Client
线程实际上并未启动。
相反,您应该将 while 循环移动到 run()
方法中。然后__init__()
方法将return控制权交给主线程,主线程可以启动线程,请求客户端通过sendData()
.
发送消息
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)
def run(self):
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 sendData(self, data):
global MESSAGES
print 'appending data:%s' % data
MESSAGES.append(data)
而不是使用全局 MESSAGES
列表,您应该创建一个 Queue
用于主线程和工作线程之间的通信,特别是如果有多个工作线程 运行。像这样的东西(未经测试!):
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")
我创建了一个 Client
套接字对象,我对其进行实例化并保持与服务器的连接,工作正常,但我想知道是否有一种方法可以调用 socket.send
来自实例外部的事件。我正准备为消息创建一个堆栈并在 while 循环中检查堆栈,如果它不为空,则将最旧的数据发送到服务器,这对我来说很好,但我的问题是堆栈仅在之后更新while 循环(我尝试突破,然后更新)。
所以我的问题是,有没有办法在 while 循环 运行 的同时更新全局堆栈?或者有没有其他方法可以在对象外调用 socket.send
事件?
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()
方法代替。
你的线程不是这样的线程,process blocks at client = Client(...).
为什么要混合 select 和线程?这真的有必要吗?如果你想在没有线程的情况下进行异步发送和接收,请使用 asyncore 模块。 或者从您的代码中删除 select。 socket.recv() 将阻塞,直到它以阻塞模式接收数据,但由于这是一个线程,我看不出有什么不妥。如果在非阻塞模式下,如果我没记错的话,如果没有要接收的数据,recv() 将只是 return None。所以你真的不需要 select。只需检查 recv() returned None。如果是,请先睡一会儿再试。
你这样做的方式让你的 OS 麻烦了两次。一次用于读取套接字,第二次用于获取套接字的状态,其中超时用于模拟 sleep() 比其他任何事情都重要。然后循环再次检查在超时后立即进行 select() 系统调用,确认该套接字无事可做。
Client.__init__()
不会 return 因为它进入了无限循环。因此,控制永远不会 return 到主线程,并且 Client
线程实际上并未启动。
相反,您应该将 while 循环移动到 run()
方法中。然后__init__()
方法将return控制权交给主线程,主线程可以启动线程,请求客户端通过sendData()
.
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)
def run(self):
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 sendData(self, data):
global MESSAGES
print 'appending data:%s' % data
MESSAGES.append(data)
而不是使用全局 MESSAGES
列表,您应该创建一个 Queue
用于主线程和工作线程之间的通信,特别是如果有多个工作线程 运行。像这样的东西(未经测试!):
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")