在 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")