使用线程python套接字客户端,该客户端在后台侦听并可以发送实时消息

时间:2018-07-23 20:29:41

标签: multithreading python-2.7 sockets queue client

我要做什么:
我正在尝试创建一个客户端脚本,该脚本可以侦听来自服务器的潜在消息并在任何时候告诉用户输入,从而告诉脚本将消息发送到服务器都在单个套接字上。我正在使用的服务器一次只能连接到一个客户端,因此所有内容都在一个套接字上。 该脚本将使用预先确定的功能(确定发送到服务器的内容)来促进maya ui和文件之间的交互。

工作原理:
我有两个线程的脚本。父线程是添加消息线程,并且有一个子线程在后台运行侦听。子线程具有恒定的后台循环,侦听来自服务器的任何消息(例如错误消息),并读取消息队列以查看是否已添加任何内容。如果将某些内容添加到队列中,侦听循环将停止,发送一条消息,然后再次启动侦听循环。父线程允许用户使用add_message()属性将命令添加到消息队列中。 maya ui将具有一些按钮,这些按钮调用一些函数以将命令添加到消息队列。我是用python 2.7制作的

这是客户端的简化示例。我在开始侦听循环之前添加了一条消息,以便可以看到它的外观。

import socket
import struct
import threading
import Queue
import time

class ThreadedClient(threading.Thread):
    def __init__(self, host, port):
        threading.Thread.__init__(self)
        #set up queues
        self.send_q = Queue.Queue(maxsize = 10)
        #declare instance variables       
        self.host = host
        self.port = port
        #connect to socket
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.s.connect((self.host, self.port))

    #LISTEN
    def listen(self):
        while True: #loop forever
            try:
                print 'checking for message...'
                # stops listening if there's a message to send
                if self.send_q.empty() == False:
                    self.send_message()
                else:
                    print 'no message'
                print 'listening...'
                message = self.s.recv(4096)
                print 'RECEIVED: ' + message
            except socket.timeout:
                pass

    def start_listen(self):
        t = threading.Thread(target = self.listen())
        t.start()
        #t.join()
        print 'started listen'


    #ADD MESSAGE
    def add_message(self, msg):
        #put message into the send queue
        self.send_q.put(msg)
        print 'ADDED MSG: ' + msg
        #self.send_message()

    #SEND MESSAGE
    def send_message(self):
        #send message
        msg = self.get_send_q()
        if msg == "empty!":
            print "nothing to send"
        else:
            self.s.sendall(msg)
            print 'SENDING: ' + msg
            #restart the listening
            #self.start_listen()


    #SAFE QUEUE READING
    #if nothing in q, prints "empty" instead of stalling program
    def get_send_q(self):       
        if self.send_q.empty():
            print "empty!"
            return "empty!"
        else:
            msg = self.send_q.get()
            return msg

if __name__ == '__main__':
    port = 8001
    address = 'localhost'
    s = ThreadedClient(address, port)
    s.start()
    print('Server started, port: ', port)

    s.add_message('hello world')
    s.start_listen()
    s.add_message('hello world')

这是客户端的示例服务器:

import socket
import sys

# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# Bind the socket to the port
server_address = ('localhost', 8001)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)

# Listen for incoming connections
sock.listen(1)

while True:
    # Wait for a connection
    print >>sys.stderr, 'waiting for a connection'
    connection, client_address = sock.accept()

    try:
        print >>sys.stderr, 'connection from', client_address

        # Receive the data in small chunks and retransmit it
        while True:
            data = connection.recv(16)
            print >>sys.stderr, 'received "%s"' % data
            if data:
                print >>sys.stderr, 'sending data back to the client'
                connection.sendall(data)
            else:
                print >>sys.stderr, 'no more data from', client_address
                break

    finally:
        # Clean up the connection
        connection.close()

问题:
一旦启动侦听循环线程,该脚本将不再接受任何输入。就像测试一样,我在启动侦听线程之后添加了一行,这将向队列添加一条消息,但没有任何反应。

以前的方法:
尽管从未解决过,但这个问题实际上也正是我正在尝试做的事情:How to handle chat client using threading and queues?

我研究了Grab user input asynchronously and pass to an Event loop in python,它涉及到创建一个接受用户输入的主循环,并尝试实现队列系统,但陷入困境。

我也尝试了How to use threading to get user input realtime while main still running in python的方法,但是对于最终的代码使用,我无法使用raw_input()。我也尝试过socket.timeout,但是也可以不输入而循环。

我正在考虑的一种方法是使脚本异步,但是据我所读,我认为它不能解决问题。

TL / DR:
有没有一种方法可以创建一个脚本,使客户端在后台监听服务器循环,同时又可以接受来自用户的实时命令?

如果能在正确的方向上提供帮助或微调,我将不胜感激,我已经坚持了一段时间。

1 个答案:

答案 0 :(得分:0)

该脚本有效。只是有些错误而已。在start_listen()函数

 t = threading.Thread(target = self.listen())

应该是

 t = threading.Thread(target = self.listen)

,然后在

之后的__init__()
self.s.connect((self.host, self.port))

添加

self.s.settimeout(.1)

以便脚本将在while循环中循环。