簡體   English   中英

在python中從外部套接字對象發送數據

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM