Reputation: 31
What I’m Trying to Do:
I’m trying to create a client script that can listen for potential messages from the server and receive input from a user at any point that tells the script to send a message to the server all on a single socket. The server I’m working with will only connect to one client at a time, so everything is on one socket.
The script will facilitate interaction between a maya ui and a file with prewritten functions that determine what to send to the server.
How it works:
I have the script with two threads. The parent thread is the adding messages thread and there is a child thread that runs the listening in the background. The child thread has a constant background loop, listening for any messages from the server (for example an error message) and reads a message queue to see if anything has been added. If something is added to the queue, the listening loop stops, sends a message, then starts the listening loop again. The parent thread allows the user to add a command into the message queue using the add_message() attribute. The maya ui will have buttons that call functions to add commands to the message queue. I made this with python 2.7
Here is an simplified example of the client. I added a single message before starting the listening loop so you can see what it is supposed to look like.
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')
And here is an example server for the client:
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()
Problem:
Once I start the listening loop thread, the script will no longer take any more input. Just as a test I added a line after starting the listening thread that would add a message to the queue and nothing happens.
Previous Approaches:
This question is essentially exactly what I’m trying to do as well, although it was never solved: How to handle chat client using threading and queues?
I have looked at Grab user input asynchronously and pass to an Event loop in python about creating a main loop that accepts user input and have tried implementing the queue system but am getting stuck.
I’ve also tried out How to use threading to get user input realtime while main still running in python approach but I can’t use raw_input()
for my final usage of the code. I have also tried socket.timeout, but also loops without taking input.
One approach I was considering was making the script asynchronous, but from what I’ve read I don’t think it will resolve the issue.
TL/DR:
Is there a way to create a script that has a client listening to the server loop running in the background while at the same time being able to accept real time commands from the user?
I would greatly appreciate any help or nudge in the right direction, I've been stuck on this a while now.
Upvotes: 2
Views: 10238
Reputation: 31
The script works. There were just some errors throwing it off. In the start_listen()
function
t = threading.Thread(target = self.listen())
should be
t = threading.Thread(target = self.listen)
and then in the __init__()
after
self.s.connect((self.host, self.port))
add
self.s.settimeout(.1)
so that the script will cycle through the while loop.
Upvotes: 1