PyQt and TCP/IP - python

OK, so i have a pretty simple turn based application (game).
Each user sends a request on the server and then wait for response. The important is, that only ONE user makes the request on the server (send his actions) and all other users are just waiting, if the server sends them some data, so they must always check (in loop) if something is coming from server.
I´m using the built-in module of python "socket" and the way i manage the clients is this: For every user i create one thread, in which runs infinite loop, until the application ends, which checks for request (if it is the turn of the user) or checks if it got anything to sent to the other users. Now let´s move to Clients. Every client has again one thread with infinite loop, waiting for data from server.
The problem is that the GUI is made in PyQt4.4, where i cant get into the loop of the PyQt itself (although i have seen, that it is possible to do this with twisted, but then i would have to rewrite my code) so i have to use the thread, that means i can use classic python threading library or QThread, but QThread sadly doesn´t have any Events, which are pretty crucial because i want always wait after the message from the server for the response of the program, so i can send response to the server again. On the other hand, I am not sure, if i can use Thread from threading to emit signals. So which one is the right one to go?
Btw: is actually ok, to run the infinite client and server side loop? Because in every tutorial I have seen, the client close the connection right after he gets his answer.
EDIT:
here´s some of the code
Server side loop for connection with client:
while self.running:
if self.is_on_turn == p and self.reply is not None:
cmd = conn.recv(1024)
if cmd == '':
conn.close()
return
cmd = eval(cmd)
if self.is_on_turn != p: # User is not on turn
print "END"
conn.sendall("END")
else:
self.queue.put(cmd)
ev.wait() # Here works another program with the message and decide what to do next
ev.clear() #
conn.sendall(str(self.message))
if self.reply:
ev.wait() #
ev.clear() #
if self.reply:
r = conn.recv(1024)
if r == '':
conn.close()
return
self.queue.put(eval(r))
ev.wait() #
ev.clear() #
conn.sendall(str(self.message))
conn.close()
Client side loop:
def main_loop(self, pipe, conn, e, o): #e is event, o is bool (whether the client has to answer back to the server)
is_on_turn = conn.recv(4096)
pipe.send((is_on_turn))
while True:
if is_on_turn == h or o.value and o.value is not None:
conn.send(str(pipe.recv()))
pipe.send(eval(conn.recv(4096)))
e.wait()
e.clear()
The pipe is there, because I made it in multiprocessing at first, there should the emit signal for the PyQt instead, but as I said, I am not sure which approach to use

So the result is, that I have just used QTcpServer and QTcpSocket as sugessted by ekhumoro, which resulted in much cleaner code and easier management :)

Related

threading does not work on UDP socket server on recv function with Tkinter

i am quite new to Python, i am trying to create a gui interface to a server and a client that shows the user data and web data.
when i try to create a threathing.Thread to the s.recv function it doesnt stop the server from freezing...
how can i make the server not freeze when he arrives to the s.recv function?
Thanks in advance!
some of my code:
def receive_message():
"""
"""
global G
s =socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((UDP_IP, UDP_PORT))
G.insert(INSERT, "Welcome to the 'Sniffer' server")
ROOT.update() # updates the Tkinter form
#time.sleep(1)
G.insert(INSERT, "\n")
while 1:
data = threading.Thread(target=s.recv(BUFFER_SIZE)).start()
if ("ip" not in format(data.decode()) and format(data.decode()).count('$') == 3):
sql = format(data.decode())
sqllist = list(sql.split("$"))
sqllist = [sqllist]
sql_connection(sqllist)
elif ("ip" not in format(data.decode()) and format(data.decode()).count('$') == 4):
sql = format(data.decode())
sqllist = list(sql.split("$"))
sqllist = [sqllist]
sql_connection2(sqllist)
if ("$" not in format(data.decode())):
G.insert(INSERT, format(data.decode()))
ROOT.update() # updates the Tkinter form
time.sleep(1)
G.insert(INSERT, "\n")
if not data:
break
You're almost there. When you call the s.recv function you actually execute it in the main thread and pass the return data to the thread. So, basically, you don't execute the s.recv function in a separate thread and this is what causes the server to freeze.
Instead, call the thread like this with arguments.
data = threading.Thread(target=s.recv, args=(BUFFER_SIZE,)).start()
There was no need to create a thread here because your code (attempts to) consume the data right away. Your problem is that you call s.recv() try to use its return value to make a thread. Its just a byte string, not a function, so nothing happens. But there are other problems. The Thread.start method returns None , not the returned data. In fact, Thread will discard the target's return value. You need a different way to save the data. That is moderately difficult and not needed here.
The solution for this code is to skip the thread entirely. There is one more subtle bug here. You want to specifically define what the encoding for your protol is. If you just use the default, that can be different on different machines. And just decode once, no need to wear out your cpu.
while 1:
data = s.recv(BUFFER_SIZE).decode('utf-8')
...etc...

Send a message to a current thread or end it in ZeroMQ with Publish/Subscribe pattern

I am using ZeroMQ and a publish/subscribe pattern, in Python.
The server sends a message, as follows:
ZMQsocket_Publisher.send(subscription_string)
which is received by a client, that, as consequence, starts a loop, like this:
loop_condition = True
while loop_condition:
ZMQsocket_Pusher.send(strings, zmq.SNDMORE)
ZMQsocket_Pusher.send(data)
during which by default infinitely responds to the server in each iteration by sending back data to the server.
The question is:
I would like to stop the while when a particular event occurs by either changing the condition or sending a break/interrupt signal. The problem I am facing right now is that if the while is still in progress, that particular client is not able to receive a "stop" message sent in a second moment by the server.
Is there an easy way to stop the while or the execution when using this pattern?
Thank you in advance!
As I understood, you have something like this:
subscription_string = your_client_receiver_socket.recv()
strings, data = some_processing(subscription_string)
loop_condition = True
while loop_condition:
ZMQsocket_Pusher.send(strings, zmq.SNDMORE)
ZMQsocket_Pusher.send(data)
If that's the case, simply add check of stop signal in while loop:
while loop_condition:
ZMQsocket_Pusher.send(strings, zmq.SNDMORE)
ZMQsocket_Pusher.send(data)
try:
stop = your_client_receiver_socket.recv(flags=zmq.DONTWAIT)
if check_on_stop(stop):
break
except zmq.error.Again:
pass
zmq.DONTWAIT flag will say receiver to receive in non-blocking way, raising zmq.error.Again exception if it couldn't receive anything. With this you can send some stop signal from server to stop client's loop.

Python client side in chat

I have a problem while trying to build the client side of a chat. I just in the begining, this is my code:
import socket
my_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
my_socket.connect(("10.10.10.69",1234))
while True:
message=raw_input("your message: ")
if(message=="quit"):
my_socket.close()
break
my_socket.send(message)
data=my_socket.recv(1024)
print "message from server:" , data
The problem is the raw_input. When a user sends a message the other users are stacked on the raw_input so only when they sends a message too they get the new messages.
How can I fix it (without using threads)?
As I commented, use select.select if your chat client is running in Unix.
For example:
import socket
import sys
import select
my_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
my_socket.connect(("10.10.10.69",1234))
sys.stdout.write('your message: ')
sys.stdout.flush()
while True:
r, w, x = select.select([sys.stdin, my_socket], [], [])
if not r:
continue
if r[0] is sys.stdin:
message = raw_input()
if message == "quit":
my_socket.close()
break
my_socket.send(message)
sys.stdout.write('your message: ')
sys.stdout.flush()
else:
data = my_socket.recv(1024)
print "message from server:" , data
raw_input holds up the thread it's in, so you can't retrieve messages in the same thread while waiting for it. Thus, I recommend using 2 threads, one which receives new messages (say every ten seconds) and one which sends messages (using code similar to the existing code).
If you're not committed to raw_input and are really against threads, you might want to look into the select module.
There are suggestions to use select() for stdin, but seems they aren't fixing the main problem. With select, imagine the local user is entering a line, and in a middle of this process your program outputs another user message, and, the editing of local input will be screwed. Either you don't allow to show new messages during entering the current one (why?) or screen is messed up. If you do this in a terminal, you should go using curses or some more powerful tool; with curses you can at least split input and output into different screen areas. Of course, a graphics library (like wxWidgets) is even more generally suitable for a user interface, if it's allowed in your case.

Using DeferredQueue for inter-task communication in Twisted

I have a Client that currently does the following:
connects
collects some data locally
sends that data to a server
repeats
if disconnected, reconnects and continues the above (not shown)
Like this:
def do_send(self):
def get_data():
# do something
return data
def send_data(data)
self.sendMessage(data)
return deferToThread(get_data).addCallback(send_data)
def connectionMade(self):
WebSocketClientProtocol.connectionMade(self)
self.sender = task.LoopingCall(self.do_send)
self.sender.start(60)
However, when disconnected, I would like the data collection to continue, probably queuing and writing to file at a certain limit. I have reviewed the DeferredQueue object which seems like what I need, but I can't seem to crack it.
In pseudo-code, it would go something like this:
queue = DeferredQueue
# in a separate class from the client protocol
def start_data_collection():
self.collecter = task.LoopingCall(self.get_data)
self.sender.start(60)
def get_data()
# do something
queue.put(data)
Then have the client protocol check the queue, which is where I get lost. Is DeferredQueue what I need, or is there a better way?
A list would work just as well. You'll presumably get lost in the same place - how do you have the client protocol check the list?
Either way, here's one answer:
queued = []
...
connecting = endpoint.connect(factory)
def connected(protocol):
if queued:
sending = protocol.sendMessage(queued.pop(0))
sending.addCallback(sendNextMessage, protocol)
sending.addErrback(reconnect)
connecting.addCallback(connected)
The idea here is that at some point an event happens: your connection is established. This example represents that event as the connecting Deferred. When the event happens, connected is called. This example pops the first item from the queue (a list) and sends it. It waits for the send to be acknowledged and then sends the next message. It also implies some logic about handling errors by reconnecting.
Your code could look different. You could use the Protocol.connectionMade callback to represent the connection event instead. The core idea is the same - define callbacks to handle certain events when they happen. Whether you use an endpoint's connect Deferred or a protocol's connectionMade doesn't really matter.

How to avoid blocking using sockets (chat client)

I've been looking around all day, but I haven't been able to fix the problem I've got with my chat client here.
Here's the issue: I recently decided to change the client so that it would allow the user to input any message they wanted without having to wait for a reply first (blocking or something stops my program until a reply is in)
I decided to use the select.select module to do so, but after writing a couple different versions of my client today trying to get it to work, I keep getting stuck at this one point.
Whenever I enter a message, the loop gets stuck somewhere, (probably at .recv data)
how can I fix this? Nothing I try gets it to go by that.
Edit: To be more clear, when I run, I get to the point where I input the message, hit enter and then nothing happens at all. It just stays running like that.
from socket import *
import select
import sys #because why not?
print("New Chat Client Using Select Module")
HOST = input("Host: ")
PORT = int(input("Port: "))
s = socket(AF_INET,SOCK_STREAM)
print("Trying to connect....")
s.connect((HOST,PORT))
s.setblocking(0)
# Not including setblocking(0) because select handles that.
print("You just connected to",HOST,)
# Lets now try to handle the client a different way!
while True:
Incoming_data = [s]
Exportable_data = []
Exceptions = []
User_input = input("Your message: ")
rlist,wlist,xlist = select.select(Incoming_data,Exportable_data,Exceptions)
if User_input == True:
Exportable_data += [User_input]
for i in rlist:
data = i.recv(1024)
if data == "":
continue
for i in wlist:
if Exportable_data is True:
i.send(Exportable_data)
continue
Is there any way I can override the blocking (that I presume is the problem) when it's set to receive data? Won't s.setblocking(0) make it so it won't block(?) (With or without it still gets stuck)
Thanks for taking a look
I think you should have separate thread or process which will interact with your socket and another thread, which will accept user input and print chat messages. Interaction between the threads you can do using 2 queues: for incoming and outgoing messages.
Have a look at threading and queue modules.

Categories

Resources