[英]Sending data from outside socket object in python
我創建了一個Client
socket對象,該對象實例化了它並使其與服務器保持有效連接,並且工作正常,但是我想知道是否有一種方法可以從實例外部調用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)
Client.__init__()
不返回,因為它進入了一個無限的while循環。 因此,控制權永遠不會返回到主線程,並且Client
線程實際上並未啟動。
相反,您應該將while循環移到run()
方法中。 然后__init__()
方法將控制權返回給主線程,該主線程隨后可以啟動該線程,並請求客戶端通過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")
如果您將循環從
__init__() into run()
方法代替。
您的線程不是這種線程,進程在client = Client(...)處阻塞。
為什么要混合選擇和線程? 這真的有必要嗎? 如果要在沒有線程的情況下異步發送和接收,請使用asyncore模塊。 或從代碼中刪除選擇。 socket.recv()將一直阻塞,直到它以阻塞模式接收數據為止,但是由於這是一個線程,因此我看不到任何錯誤。 如果在非阻塞模式下,如果我沒有記錯的話,recv()將在沒有數據要接收的情況下僅返回None。 因此,您實際上不需要選擇。 只需檢查recv()是否返回None。 如果是這樣,請稍等片刻再嘗試。
您的操作方式使您的OS遭受了兩次麻煩。 一次用於讀取套接字,第二次獲取套接字的狀態,其中超時用於模擬sleep()而不是其他任何東西。 然后,在超時確認對該套接字沒有任何作用之后,循環再次檢查是否使select()系統調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.