Python async socket recv not working - python

Here is a simple client which connects and sends a text message:
class Client(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.connect( (host, port) )
self.buffer = bytes("hello world", 'ascii')
def handle_connect(self):
pass
def handle_close(self):
self.close()
def handle_read(self):
print(self.recv(8192))
def writable(self):
return (len(self.buffer) > 0)
def writable(self):
return True
def handle_write(self):
sent = self.send(self.buffer)
print('Sent:', sent)
self.buffer = self.buffer[sent:]
client = Client('localhost', 8080)
asyncore.loop()
And here is the server which has to receive the message and echo it back:
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_read(self):
self.buffer = self.recv(4096)
while True:
partial = self.recv(4096)
print('Partial', partial)
if not partial:
break
self.buffer += partial
def readable(self):
return True
def handle_write(self):
pass
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
self.handle_read()
print(self.buffer)
if __name__ == "__main__":
server = Server("localhost", 8080)
asyncore.loop()
The problem is that server isn't reading anything. When I print self.buffer the output is:
b''
What am I doing wrong?

First of all, you need two handlers: One for the server socket (where you expect only accept), and one for the actual communication sockets. In addition, you can only call read once in handle_read; if you call it twice, the second call may block, and that's not allowed in asyncore programming. Don't worry though; if your read did not get everything, you'll immediately be notified again once your read handler returns.
import asyncore
class Handler(asyncore.dispatcher):
def __init__(self, sock):
self.buffer = b''
super().__init__(sock)
def handle_read(self):
self.buffer += self.recv(4096)
print('current buffer: %r' % self.buffer)
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accepted(self, sock, addr):
print('Incoming connection from %s' % repr(addr))
Handler(sock)
if __name__ == "__main__":
server = Server("localhost", 1234)
asyncore.loop()

Related

Object Orientated Socket Python Client Server. Pass Modified Client Message to Server

I am trying to build a Python program that will pass a message between a Client and Server. The idea is to pass one message from the Server and have the Client modify it and pass it back to the Server.
Right now I am suck on trying to get the Client's message back to the Server; the message 'Congrats! You have connected' is converted to uppercase,
Server
import socket
class Server:
def __init__(self, host, port):
self.serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.host = host
self.port = port
def bind(self):
self.serverSocket.bind((self.host, self.port))
self.serverSocket.listen(5)
def run(self):
while True:
print ('Waiting for a connection')
(clientSocket, addr) = self.serverSocket.accept()
print ('Got a connection from {}'.format(str(addr)))
message = 'Congrats! You have connected'
self.sendMessage(message, clientSocket)
self.recieveMessage()
clientSocket.close()
def sendMessage(self, message, clientSocket):
clientSocket.send(message.encode('ascii'))
def recieveMessage(self):
(clientSocket, addr) = self.serverSocket.accept()
message = self.serverSocket.recv(1024).decode('ascii')
print(message)
def closeSocket(self):
self.serverSocket.close()
if __name__ == '__main__':
myServer = Server('127.0.0.1', 5555)
myServer.bind()
myServer.run()
myServer.recieveMessage()
myServer.closeSocket()
Client
import socket
class Client:
def __init__(self, host, port):
self.serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = host
self.port = port
def connect(self):
self.serverSocket.connect((self.host, self.port))
def getMessage(self):
return self.serverSocket.recv(1024).decode('ascii')
def modifyMessage(self):
return message.upper()
def sendMessage(self, upperCaseMessage, server):
(server, addr) = self.serverSocket.accept()
serverSocket.send(upperCaseMessage.encode('ascii'))
def closeConnection(self):
self.serverSocket.close()
if __name__ == '__main__':
myClient = Client('127.0.0.1', 5555)
myClient.connect()
message = myClient.getMessage()
upperCaseMessage = myClient.modifyMessage()
myClient.sendMessage(upperCaseMessage, serverSocket)
myClient.closeConnection()

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?

Converting Twisted Code to Asyncio Code

I have a code which is written in Twisted and I am having trouble with converting it to Asyncio. From my problem the problem is about protocol in Server class. The code which is written with Twisted is this:
from twisted.internet import reactor, protocol
class Client():
def __init__(self):
self.something = ""
def dataReceived(self, packet):
print(packet)
def makeConnection(self, transport):
self.transport = transport
self.server = self.factory
def connectionLost(self, args):
print("Connection lost.")
class Server(protocol.ServerFactory):
protocol = Client
if __name__ == '__main__':
validPort = []
S = Server()
try:
reactor.listenTCP(44444, S)
validPort.append(44444)
except:
print('Problem about port.')
if not validPort == []:
print('Server is running.')
reactor.run()
And this is the code which I converted to Asyncio and doesnt't work (I am not sure the problem is about protocol in Server Class):
import asyncio, logging, sys
SERVER_ADDRESS = ('localhost', 44444)
logging.basicConfig(
level=logging.DEBUG,
format='%(name)s: %(message)s',
stream=sys.stderr,
)
log = logging.getLogger('main')
event_loop = asyncio.get_event_loop()
class Client():
def __init__(self):
self.something = ""
def data_received(self, packet):
self.log.debug('received {!r}'.format(data))
print(packet)
def connection_made(self, transport):
self.transport = transport
self.server = self.factory
self.log = logging.getLogger(
'EchoServer_{}_{}'.format(*self.address)
)
self.log.debug('connection accepted')
def connection_lost(self, args):
if error:
self.log.error('ERROR: {}'.format(error))
else:
self.log.debug('closing')
super().connection_lost(error)
class Server(asyncio.Protocol):
protocol = Client
if __name__ == '__main__':
S = Server()
factory = event_loop.create_server(S, *SERVER_ADDRESS)
server = event_loop.run_until_complete(factory)
log.debug('starting up on {} port {}'.format(*SERVER_ADDRESS))
try:
event_loop.run_forever()
finally:
log.debug('closing server')
server.close()
event_loop.run_until_complete(server.wait_closed())
log.debug('closing event loop')
event_loop.close()
In asyncio there is no ProtocolFactory abstract interface. Just pass Client or lambda: Client to loop.create_server()

Python: UDP echo server asyncore ; socket closing after send

I'm trying to write a UDP server that echos data back using asyncore.dispatcher_with_send
The problem i have is that when i set the buffer and call self.send(self.buffer), it seems to call handle_close and closes the socket.
import asyncore, socket,
class Server(asyncore.dispatcher_with_send):
def __init__(self):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
self.bind(('192.168.0.10', 1452))
self.buffer = ''
self.recvData = ''
def handle_close(self):
self.close()
def handle_read(self):
print self.recv(8192)
self.buffer ='a'
def handle_write(self):
if self.buffer != '':
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
if __name__ == '__main__':
The_Server = Server()
asyncore.loop()
Any Ideas?
Thanks
The solution was to use sendto and to make sure the sendto address was explicit.
import asyncore, socket,
class Server(asyncore.dispatcher_with_send):
def __init__(self):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_DGRAM)
self.bind(('192.168.0.10', 1452))
self.buffer = ''
self.recvData = ''
def handle_close(self):
self.close()
def handle_read(self):
print self.recv(8192)
self.buffer ='a'
def handle_write(self):
if self.buffer != '':
sent = self.sendto(self.buffer,('192.168.0.9',1452))
self.buffer = self.buffer[sent:]
if __name__ == '__main__':
The_Server = Server()
asyncore.loop()

UDP client and server with Twisted Python

I want to create a server and client that sends and receives UDP packets from the network using Twisted. I've already written this with sockets in Python, but want to take advantage of Twisted's callback and threading features. However, I need help though with the design of Twisted.
I have multiple types of packets I want to receive, but let's pretend there is just one:
class Packet(object):
def __init__(self, data=None):
self.packet_type = 1
self.payload = ''
self.structure = '!H6s'
if data == None:
return
self.packet_type, self.payload = struct.unpack(self.structure, data)
def pack(self):
return struct.pack(self.structure, self.packet_type, self.payload)
def __str__(self):
return "Type: {0}\nPayload {1}\n\n".format(self.packet_type, self.payload)
I made a protocol class (almost direct copy of the examples), which seems to work when I send data from another program:
class MyProtocol(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
p = Packet(data)
print p
reactor.listenUDP(3000, MyProtocol())
reactor.run()
What I don't know is how do I create a client which can send arbitrary packets on the network, which get picked up by the reactor:
# Something like this:
s = Sender()
p = Packet()
p.packet_type = 3
s.send(p.pack())
p.packet_type = 99
s.send(p.pack())
I also need to make sure to set the reuse address flag on the client and servers so I can run multiple instances of each at the same time on the same device (e.g. one script is sending heartbeats, another responds to heartbeats, etc).
Can someone show me how this could be done with Twisted?
Update:
This is how I do it with sockets in Python. I can run multiple listeners and senders at the same time and they all hear each other. How do I get this result with Twisted? (The listening portion need not be a separate process.)
class Listener(Process):
def __init__(self, ip='127.0.0.1', port=3000):
Process.__init__(self)
self.ip = ip
self.port = port
def run(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((self.ip, self.port))
data, from_ip = sock.recvfrom(4096)
p = Packet(data)
print p
class Sender(object):
def __init__(self, ip='127.255.255.255', port=3000):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ip = (ip, port)
def send(self, data):
self.sock.sendto(data, self.ip)
if __name__ == "__main__":
l = Listener()
l.start()
s = Sender()
p = Packet()
p.packet_type = 4
p.payload = 'jake'
s.send(p.pack())
Working solution:
class MySender(DatagramProtocol):
def __init__(self, packet, host='127.255.255.255', port=3000):
self.packet = packet.pack()
self.host = host
self.port = port
def startProtocol(self):
self.transport.write(self.packet, (self.host, self.port))
if __name__ == "__main__":
packet = Packet()
packet.packet_type = 1
packet.payload = 'jake'
s = MySender(packet)
reactor.listenMulticast(3000, MyProtocol(), listenMultiple=True)
reactor.listenMulticast(3000, s, listenMultiple=True)
reactor.callLater(4, reactor.stop)
reactor.run()
Just like the server example above, there is a client example to.
This should help you get started:
https://twistedmatrix.com/documents/current/core/howto/udp.html
https://github.com/twisted/twisted/blob/trunk/docs/core/examples/echoclient_udp.py
Ok, here is a simple heart beat sender and receiver using datagram protocol.
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time
class HeartbeatSender(DatagramProtocol):
def __init__(self, name, host, port):
self.name = name
self.loopObj = None
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
# I am ready to send heart beats
self.loopObj = LoopingCall(self.sendHeartBeat)
self.loopObj.start(2, now=False)
def stopProtocol(self):
"Called after all transport is teared down"
pass
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
def sendHeartBeat(self):
self.transport.write(self.name, (self.host, self.port))
class HeartbeatReciever(DatagramProtocol):
def __init__(self):
pass
def startProtocol(self):
"Called when transport is connected"
pass
def stopProtocol(self):
"Called after all transport is teared down"
def datagramReceived(self, data, (host, port)):
now = time.localtime(time.time())
timeStr = str(time.strftime("%y/%m/%d %H:%M:%S",now))
print "received %r from %s:%d at %s" % (data, host, port, timeStr)
heartBeatSenderObj = HeartbeatSender("sender", "127.0.0.1", 8005)
reactor.listenMulticast(8005, HeartbeatReciever(), listenMultiple=True)
reactor.listenMulticast(8005, heartBeatSenderObj, listenMultiple=True)
reactor.run()
The broadcast example simply modifies the above approach:
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
from twisted.internet.task import LoopingCall
import sys, time
class HeartbeatSender(DatagramProtocol):
def __init__(self, name, host, port):
self.name = name
self.loopObj = None
self.host = host
self.port = port
def startProtocol(self):
# Called when transport is connected
# I am ready to send heart beats
self.transport.joinGroup('224.0.0.1')
self.loopObj = LoopingCall(self.sendHeartBeat)
self.loopObj.start(2, now=False)
def stopProtocol(self):
"Called after all transport is teared down"
pass
def datagramReceived(self, data, (host, port)):
print "received %r from %s:%d" % (data, host, port)
def sendHeartBeat(self):
self.transport.write(self.name, (self.host, self.port))
class HeartbeatReciever(DatagramProtocol):
def __init__(self, name):
self.name = name
def startProtocol(self):
"Called when transport is connected"
self.transport.joinGroup('224.0.0.1')
pass
def stopProtocol(self):
"Called after all transport is teared down"
def datagramReceived(self, data, (host, port)):
now = time.localtime(time.time())
timeStr = str(time.strftime("%y/%m/%d %H:%M:%S",now))
print "%s received %r from %s:%d at %s" % (self.name, data, host, port, timeStr)
heartBeatSenderObj = HeartbeatSender("sender", "224.0.0.1", 8005)
reactor.listenMulticast(8005, HeartbeatReciever("listner1"), listenMultiple=True)
reactor.listenMulticast(8005, HeartbeatReciever("listner2"), listenMultiple=True)
reactor.listenMulticast(8005, heartBeatSenderObj, listenMultiple=True)
reactor.run()
Check out the echoclient_udp.py example.
Since UDP is pretty much symmetrical between client and server, you just want to run reactor.listenUDP there too, connect to the server (which really just sets the default destination for sent packets), then transport.write to send your packets.

Categories