Server is sending quicker than client can recv - python

my server sends objects much faster than the client receives. That's why the client receives the objects that were sent 10 seconds ago because the client has to receive every object that is in the queue. So my question is: How do I slow the server down or make my client receiving faster?
Edit: I added time.sleep(0.1) to the server but is there a more efficient way?
This is my Network class:
import socket
import pickle
class Network:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server = "192.168.1.15"
self.port = 5555
self.addr = (self.server, self.port)
self.player = self.connect()
def get_player(self):
return self.player
def connect(self):
try:
self.client.connect(self.addr)
except:
pass
def send_object(self, data):
self.client.send(pickle.dumps(data))
def get_object(self):
return pickle.loads(self.client.recv(1024))
def send_msg(self, data):
self.client.send(bytes(data, "utf-8"))
def get_msg(self):
return self.client.recv(1024).decode("utf-8")
and my server when it's sending:
p_count = conn.recv(1024).decode("utf-8")
if p_count:
games.append(Game(game_id, int(p_count), ip))
game_id += 1
while True:
conn.send(pickle.dumps(games[-1]))
and my client when it's receiving:
def update(self):
global bg_surface
try:
self.game = n.get_object()
self.player_in = self.game.players_ready
bg_surface = pygame.image.load('./bilder/background3.jpg').convert()
bg_surface = pygame.transform.scale(bg_surface, (screen_width, screen_height))
self.warte_text = Label(f"Warte auf Spieler {self.player_in}/{self.player_amount}", 20, (screen_width // 2, screen_height // 2 * 0.25), (255, 0, 0))
self.warte_text.update(bg_surface)
except:
pass

The efficient way to handle this is to have your server call select() or poll() on the socket to find out when the socket has room in its outgoing-data-buffer (and optionally block until there is room) and only generate and send() data to the socket when the socket has indicated it is ready-for-write. That way your server-thread doesn't get blocked waiting for the client to read data, no matter how slow the client is at reading.

Related

Why sending a simple string message from client to PodSixNet server is not working

How to make my first communication between client and server by sending a simple string message, I've followed all the documentation, tutorials and topics based on PodSixNet and I can't do it in any way for a few days..
Thank you very much!
Server Code
`
from PodSixNet.Channel import Channel
from PodSixNet.Server import Server
from time import sleep
class ClientChannel(Channel):
def Network(self, data):
print(data)
def Network_myaction(self, data):
print("myaction", data)
class MyServer(Server):
channelClass = ClientChannel
def Connected(self, channel, addr):
print('New connection: {}'.format(channel, addr))
if __name__ == "__main__":
print("Server starting on LOCALHOST...\n")
myserver = MyServer(localaddr=('MyLocalIP', 1337))
while True:
myserver.Pump()
sleep(0.0001)
Client Code
from PodSixNet.Connection import ConnectionListener
from PodSixNet.Connection import connection
from time import sleep
class DouaIntrebari(ConnectionListener):
def __init__(self, host, port, **kwargs):
self.Connect((host, port))
super().__init__(**kwargs)
self.say = "Message Received !"
self.nr1 = 1
self.nr2 = 2
self.running = False
while not self.running:
self.Pump()
connection.Pump()
sleep(0.01)
def send_info(self):
if self.nr1 < self.nr2:
self.Send({"action": "zice", "say": self.say})
if __name__ == "__main__":
print("Client started.\n")
DouaIntrebari('MyLocalIP', 1337)
`
I tried to trigger a method to send the string message to the server but nothing happens...

Problem with object oriented comparisons when threading in python

im not too bad at python, and ive tried to make a threaded socket client, but ive hit a problem in my code that i cant solve. Here is the code:
import socket
import threading
class ThreadedServer(object):
def __init__(self, host, port, num):
self.num = num
self.host = host
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind((self.host, self.port))
def listen(self):
self.sock.listen(1)
while True:
client, address = self.sock.accept()
client.settimeout(600)
threading.Thread(target = self.listenToClient,args = (client,address)).start()
def listenToClient(self, client, address):
size = 1024
# fix this, please
if self.num == 1:
print("Client 1 connected")
if self.num == 2:
print("Client 2 connected")
if self.num == 3:
print("Client 3 connected")
while True:
data = client.recv(size)
data = data.decode("utf-8")
print("Client", self.num, ": ", data)
# Reply
if data == "lad":
response = "nice"
else:
response = data
client.send(response.encode('utf-8'))
if __name__ == "__main__":
while True:
host = input("Host? ")
port_num = input("Port? ")
try:
port_num = int(port_num)
print("Please connect client")
break
except ValueError:
pass
ThreadedServer(host,port_num, 1).listen()
ThreadedServer(host,port_num, 2).listen()
ThreadedServer(host,port_num, 3).listen()
ThreadedServer.listenToClient()
You see, when i run this, i also connect it to a rather simple client, which sends me data.
In this code, the data i receive is amply called 'data'.
The problem i have in this code is that in the section where i repeat 'if self.num:', i plan for it to give me the following code when i connect 3 client:
Client 1 connected
Client 2 connected
Client 3 connected
but instead it simply repeats 'Client 1 connected' 3 times.
It would be great if anyone could try to solve this problem for me, thanks in advance
Ps: If anyone would like the client too, just ask for it, and i will edit this post to add it in.
You get correct output according to the code you run. Your code has two problems. The first problem is in the main suite. Look at the line ThreadedServer(host,port_num, 1).listen(). It says: create object of class ThreadServer and call method listen() which runs forever (listens to connections forever). You will never start 2 more servers ThreadedServer(host,port_num, 2).listen() and ThreadedServer(host,port_num, 3).listen(). This is good but should be fixed. So you have 1 server which can accept multiple connections. But you count servers instead of clients (this is the second problem which gives you the output you do not expect).
The solution is the following.
Run only 1 server (1 object of class ThreadedServer).
Add counter to the method listen():
def listen(self):
counter = 0
self.sock.listen(1)
while True:
client, address = self.sock.accept()
client.settimeout(600)
counter += 1
threading.Thread(
target=self.listenToClient,
args=(client, address, counter)).start()
Change method listenToClient() a little bit:
def listenToClient(self, client, address, client_id):
size = 1024
print("Client {} connected".format(client_id))
while True:
data = client.recv(size)
data = data.decode("utf-8")
print("Client", self.num, ": ", data)
# Reply
if data == "lad":
response = "nice"
else:
response = data
client.send(response.encode('utf-8'))
And you will get output:
Client 1 connected
Client 2 connected
Client 3 connected

Mouse remote control

Trying to implement some kind of synergy on python using PyAutoGui and socket communication.
The idea is to control mouse and keyboard of another computer on LAN by using mouse/keyboard of a server computer.
By now it's only mouse movement implementaion.
Here are some classes:
Server part:
class Server:
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.ip = get_ip()
self.port = 3000
self.transfer_mod = False
self.client_address = ""
def start(self):
print("Started server with ip: {}".format(self.ip))
self.s.bind((self.ip, self.port))
self.get_connection()
def get_connection(self):
print("Waiting for connection...")
while True:
request, self.client_address = self.s.recvfrom(4096)
if request:
self.s.sendto(request, self.client_address)
print("{} connected!".format(self.client_address))
break
def enable_transfer(self):
print("Transfer to {} enabled".format(self.client_address))
self.transfer_mod = True
transfer_thread = threading.Thread(target=self.transfer_mouse)
transfer_thread.start()
def disable_transfer(self):
print("Transfer to {} disabled".format(self.client_address))
self.transfer_mod = False
def transfer_mouse(self):
previous_pos = (-1, -1)
while self.transfer_mod:
pos = pyautogui.position()
if pos != previous_pos:
data = pickle.dumps(pos)
self.s.sendto(data, self.client_address)
sleep(0.1)
previous_pos = pos
def close(self):
self.disable_transfer()
self.s.close()
Client part:
class Client:
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.port = 3000
self.connection = False
def connect(self, server_ip):
request = bytes("Request","utf-8")
self.s.sendto(request, (server_ip, self.port))
received, address = self.s.recvfrom(4096)
if received == request:
print("Connected to {}".format(server_ip))
self.connection = True
threading.Thread(target=self.receive_data).start()
def receive_data(self):
while self.connection:
data, server = self.s.recvfrom(4096)
pos = pickle.loads(data)
self.control_mouse(pos)
def disconnect(self):
print("Disconnected from the server")
self.connection = False
def control_mouse(self, position):
pyautogui.moveTo(position[0], position[1])
def close(self):
self.disconnect()
self.s.close()
So, the problem of that is the speed of mouse movement on client computer is so low. It seems there are too many exceed packets or something like that. So, the question itself: Is it a good way of implementing this idea, if yes, what's the problem of that script, if no, any advises on how to do it more properly?

Python: How do I lock an object until all threads have done a thing

I am writing a simple threaded server that will send a message to all clients. I have an object that is reset after posting the change message, however I am having a hard time figuring out how to reset that object only after all threads have posted the change message.
To add some context to the problem. I am building a multi user Tkinter python app which connects to a remote database to retrieve information and the application needs to know when data changes so that when a user updates data, all other running instances of the app will get the update. From what I understand, MySQL does not support asynchronous application updates. Instead of running a query every 5 seconds on the database to see if there is a change, I am putting this code server side so that it will send a message to a socket on the client that a change has occurred on the database.
The main loop is just a dummy that will simulate a change
Here is my code:
import socket, threading, time, select, os
class dbMonitor:
isDBAltered = False
def postChange(self):
self.isDBAltered = True
def __str__(self):
return str(self.isDBAltered)
class ThreadedServer(object):
def __init__(self, port,dbMon):
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setblocking(0)
self.sock.bind((socket.gethostname(), self.port))
self.dbMon = dbMon
def listen(self):
self.sock.listen(100)
read_list = [self.sock]
while True:
read,write,error = select.select(read_list,[],[],1)
for s in read:
if s is self.sock:
client, address = self.sock.accept()
client.settimeout(60)
threading.Thread(target = self.listenToClient, args = (client,address)).start()
def listenToClient(self, client, address):
read_list = [client]
size = 1024
while True:
response = b'Ack'
if self.dbMon.isDBAltered:
response = b'CHANGE'
try:
client.send(response)
except:
client.close()
return False
self.dbMon.isDBAltered = False
read,write,error = select.select(read_list,[],[],1)
for s in read:
if s is client:
try:
data = client.recv(size)
print(data)
if data:
client.send(response)
else:
raise error('Client disconnected')
except:
client.close()
return False
def mainLoop():
while True:
time.sleep(15)
print(dbMon)
dbMon.postChange()
dbMon = dbMonitor()
server = ThreadedServer(5005,dbMon)
threading.Thread(target = mainLoop, args=()).start()
threading.Thread(target = server.listen(), args=()).start()
How do I get self.dbMon.isDBAltered = False to execute only after all threads have executed:
response = b'CHANGE'
try:
client.send(response)
You're trying to synchronize something that's asynchronous... This is massively more complicated than it should be. Your dbmon is only storing a boolean flag... why not just asynchronously modify the "database" instead? For example, if the "database" was a thread-safe buffer, you could just append to that buffer or modify that buffer without synchronizing each thread individually, pull the information written to that buffer and write it to the client socket they belong to in another event loop (this is pretty much what asyncore does)
That said, I have some (probably nonworking, but I hope you get the idea) reference modified code for you to go off of if you want to continue pursing this avenue.
Basically, dbmon will keep a mapping of thread ids to [creation time, modified flag]
Our predicate returns true iff all threads created before a certain threshold have ALL set the modified flag. We set the modified flag when we send the response in the data = client.recv(size) portion of your code. And then we wait on that condition in the server send. We keep notifying all waiting threads on each client receive so that when the condition is finally met, our waiting server threads will all unblock and send the subsequent response.
import socket, threading, time, select, os
import collections
class dbMonitor:
def __init__(self):
self.isDBAltered = {}
self.lock = threading.Lock()
def newThread(self, tid):
self.lock.acquire()
# time of creation, boolean whether that thread has sent response
self.isDBAltered[tid] = [time.time(), False]
self.lock.release()
def threadDone(self, tid):
self.lock.acquire()
self.isDBAltered.pop(tid, None)
self.lock.release()
def altered(self, tid):
self.lock.acquire()
self.isDBAltered[tid][1] = True
self.lock.release()
def reset(self, tid):
self.lock.acquire()
self.isDBAltered(tid)[1] = False
self.lock.release()
def __str__(self):
return str(self.isDBAltered)
class ThreadedServer(object):
def __init__(self, port,dbMon):
self.port = port
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.setblocking(0)
self.sock.bind((socket.gethostname(), self.port))
self.dbMon = dbMon
self.lock = threading.lock()
self.cv = threading.Condition()
self.thresh = 2000
def condition_pred(self):
# unblock if threads currently running for longer than self.thresh have all set their flags
return all([timecreate[1] if time.time() - timecreate[0] > self.thresh else True for tid,timecreate in self.dbMon.isDBAltered])
def listen(self):
self.sock.listen(100)
read_list = [self.sock]
while True:
read,write,error = select.select(read_list,[],[],1)
for s in read:
if s is self.sock:
self.lock.acquire()
client, address = self.sock.accept()
client.settimeout(60)
T = threading.Thread(target = self.listenToClient, args = (client,address)).start()
self.dbmon.newThread(T.ident)
self.lock.release()
def listenToClient(self, client, address):
read_list = [client]
size = 1024
while True:
response = b'Ack'
with self.cv:
self.cv.wait_for(self.condition_pred)
self.dbMon.reset(threading.get_ident())
response = b'CHANGE'
try:
client.send(response)
except:
client.close()
self.dbmon.threadDone(threading.get_ident())
return False
read,write,error = select.select(read_list,[],[],1)
for s in read:
if s is client:
with self.cv:
try:
data = client.recv(size)
print(data)
if data:
client.send(response)
self.dbMon.altered(threading.get_ident())
self.cv.notifyAll()
else:
raise error('Client disconnected')
except:
client.close()
self.dbmon.threadDone(threading.get_ident())
return False

python stop multithreaded echo server

I tried to create multithreaded echo server:
echomain.py:
#!/usr/bin/python
from echoserver import echoserver
server = echoserver()
print server.isRunning()
print server.port()
server.start()
print "Main program continues..."\\This part is not displayed(((
echoserver.py:
#!/usr/bin/python
import threading
import socket
class connection(threading.Thread):
def __init__(self, sock, addr):
self.sock = sock
self.addr = addr
threading.Thread.__init__(self)
def run (self):
while True:
buffer = self.sock.recv(1024)
if buffer == "disconnect\r\n":
self.sock.send("bye")
break
elif buffer:
self.sock.send(buffer)
self.sock.close()
class echoserver(object):
def __init__(self, port=12119):
self.running = False
self._port = port
self._socket = None
def isRunning(self):
return self.running
def port(self):
return self._port
def start(self):
self.running = True
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind(("0.0.0.0", self.port()))
self._socket.listen(5)
while True:
conn, addr = self._socket.accept()
connection(conn, addr).start()
def stop(self):
self._socket.close()
print "Server is closed..."
Could somebody help me in how I can launch echoserver class as a thread so it run simultaneously with main program so I could stop it with stop() method in echomain.py part?
Change your runner program to run the server as a thread:
echomain.py:
#!/usr/bin/python
from echoserver import echoserver
from threading import Thread
import time
server = echoserver()
print server.isRunning()
print server.port()
# server.start()
# run server in a different thread
serverThread = Thread(target=server.start)
serverThread.start()
print "main - server started"
# wait ten seconds before stopping
time.sleep(10)
server.stop()
print "main - server stopped"
print "Main program continues..."
This example simply stops the server after 10 seconds.
The simplest way is to have your echoserver itself be a Thread as proposed by Reut Sharabani, but IMHO, you should also implement a correct stop() method, ensuring that all children have ended.
Here is my implementation of your script :
#!/usr/bin/python
import threading
import socket
class connection(threading.Thread):
def __init__(self, sock, addr, parent):
self.sock = sock
self.addr = addr
self.parent = parent
threading.Thread.__init__(self)
self.sock.settimeout(None)
self.closed = False # will be set to True on thread end
def run (self):
while not self.parent._stopped:
buffer = self.sock.recv(1024)
if buffer == "disconnected\r\n":
self.sock.send("bye")
break
elif buffer:
self.sock.send(buffer)
self.sock.close()
self.closed = True
class echoserver(threading.Thread):
def __init__(self, port=12119):
threading.Thread.__init__(self)
self.running = False
self._port = port
self._socket = None
self._stopped = False
self._conns = [] # list of active connections
def isRunning(self):
return self.running
def port(self):
return self._port
def run(self):
self.running = True
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self._socket.bind(("0.0.0.0", self.port()))
self._socket.listen(5)
self._socket.settimeout(5) # use a timeout to respond to stop()
while not self._stopped:
try:
conn, addr = self._socket.accept()
c = connection(conn, addr, self)
self._conns.append(c) # add child the the list
c.start()
except Exception as e:
# print e # in debug
pass
self._conns = self.child_list() # remove closed child from list
self._socket.close()
print "Server is closing..."
for connect in self._conns: # join active children
connect.join()
print "Server is closed"
def stop(self):
self._stopped = True
def child_list(self):
l = []
for conn in self._conns:
if conn.closed:
conn.join()
else:
l.append(conn)
return l
Remarks :
you simply use it that way :
serv=echoserver()
serv.start()
... # sleep of do anything you want
serv.stop()
if no connection is active when you call stop() all stops at the end of the accept timeout and you get :
Server is closing...
Server is closed
if at least one connection is active when you call stop(), you get only Server is closing... at the end of the accept timeout. Then for each connection, it will end as soon as it receives a packet, and will be joined by echoserver. Then when all connection are over, you will get Server is closed and echoserver thread will terminate
that means that in you main thread you have only to do
serv.stop()
serv.join()
to be sure that all other threads are correctly terminated, and that all sockets are closed

Categories