Handle IPV6 adresses in Python asyncio - python

I'm trying to use asyncio to create a connection to a TCP server in IPV6. This is not working, this function below fails to get the IPv6 server address:
def connection_made(self, transport: transports.BaseTransport) -> None:
peername = transport.get_extra_info('peername')
self.__ip = peername[0]
print('Connection from {}'.format(peername))
# database operation
AckTlvDB.product_online(peername[0], datetime.now())
what is the right way to do it?
my client code :
async def run_client():
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
loop = asyncio.get_event_loop()
on_con_lost = loop.create_future()
transport, protocol = await loop.create_connection(
lambda: AckTlvProtocol(on_con_lost), sock=sock ) # put SERVER6ADDR & SEVERPORT instead of "sock" not working to
try:
await on_con_lost
finally:
transport.close()

Related

How to handle websocket traffic in Python Websocket?

I can use websockets in my code and i can easily store it some list. Here is code
import websockets
import asyncio
clients = {}
async def handle_connection(websocket, path):
# save websocket connection in clients dictionary
clients[websocket] = path
try:
# messages from client
async for message in websocket:
for to_client in clients.keys():
dest_username = clients[to_client]
source_username = clients[websocket]
text_data = message
if source_username == dest_username:
await to_client.send(f"{source_username}: {text_data}")
except Exception as e:
print(e)
finally:
# remove websocket connection
clients.pop(websocket)
# websocket server port
PORT = 5678
start_server = websockets.serve(handle_connection, 'localhost', PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
My question is this, is it the correct way to store all websockets in a list ? Because i can not find any example for storing websockets.Some adviced tornado.But are there any best(optimal) solution ? Thank you for your answers

server stop receiving msg after 1 msg receive

The idea is to create a server for sending and receiving files for backup, right now the server receives 1 msg from a client in python and another in C++, the problem is, the python client manages to send 1 string and then the server kinda looks, and I have to end the connection, that's for the python client, when I'm trying to send data from the c++ client i got nothing
I'm using Websockets, but my problem seems to be on the try: statement, honestly cant figure it out wheres my problem
sidenote: I'm using quit() to stop my program, but every time I used it I got way too many errors so I had to comment it
Here's my Server.py code
import asyncio
import websockets
import socket
import sqlite3
import sys
def get_ip(): # returns primary private IP only
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
async def handle_connectio(websocket, path): # recive and handle connection from client, would handle json or file data
while True:
try:
async for name in websocket:
#name = await websocket.recv()
print(f"<<< {name}")
#break
except websockets.exceptions.ConnectionClosed:
print (f"Coneecion terminada")
#quit()
break
else:
print (f"algo paso")
#quit()
break
print ("Iniciando el Server webSocket")
print ("Current Ip: " + get_ip())
servidor = websockets.serve(handle_connectio, get_ip(), 8000)
#loop = asyncio.get_event_loop()
#loop.run_until_complete(servidor)
asyncio.get_event_loop().run_until_complete(servidor)
asyncio.get_event_loop().run_forever()
#async def main(): # main function
# print ("Iniciando Server websocket")
# print("Current Ip: " + get_ip())
# async with websockets.serve(handle_connectio, get_ip(), 8000):
# await asyncio.Future()
#if __name__ == '__main__':
# asyncio.run(main())
edit: I did try to simplify my code and it manages to receive the msg and show when the connection is closed - still the main problem persists.
async def handle_connectio(websocket, path): # recive and handle connection from client, would handle json or file data
try:
while True:
#async for data in websocket:
data = await websocket.recv()
print(f"<<< {data}")
await asyncio.sleep(1)
except websockets.exceptions.ConnectionClosed:
print (f"Coneecion terminada")
edit2: heres my client code, if this donst work i would switch to sockets
import asyncio
import websockets
async def client():
direc = "ws://192.168.1.69:8000"
async with websockets.connect(direc) as web:
while True:
nombre = input("Introduce el mensaje >>> ")
await web.send(nombre)
asyncio.get_event_loop().run_until_complete(client())
From looking at and running the example code at https://websockets.readthedocs.io/en/stable/, it's apparent that your connection handler shouldn't loop forever (while True:) but exit after handling all the messages supplied by the websocket. It will be called again when another message arrives.
Edit:
The original server code works fine. The problem is that the client is using the input() function, which blocks asyncio from running, which prevents websocket protocol from running correctly and blocks messages from sending. A small delay after send (await asyncio.sleep(1)) works, although ideally the input() and the asyncio comm logic would be separated, to avoid an arbitrary delay.
Ok for some odd reason websockets wont work/behave properly so i had to switch to Sockets and now i can send the data back and forth, i would post my client and server code for anyone on the future.
Server.py
import socket
# socket.SOCK_STREAM -> TCP
# socket.SOCK_DGRAM -> UDP
def get_ip(): # returns primary private IP only
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
def servidor():
print (f"Iniciando el Servidor Sockets")
print (f"Current IP Addres: " + get_ip())
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((get_ip(), 8000))
server.listen(1)
conn, address = server.accept() # Accept the Client connection
while True:
#1024 is the bandwidth bits
try:
msg = conn.recv(1024).decode() # Recive the msg and trasform it from Binary to String
print("<<< " + msg)
except:
print (f"coneccion terminada")
break
if __name__ == "__main__":
servidor()
Client.py
import socket
print ('Iniciando cliente')
conn_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
conn_client.connect( ('192.168.1.68', 8000))
while True:
try:
msg = (f">>> ")
conn_client.sendall(msg.encode())
except:
print (f"Connection Close")
break
#recibido = conn_client.recv(1024)
#print (recibido.decode())
conn_client.close()

No print message from socket server, reciving response from client sent message

I am setting up a client/server in Python with the ability to handle multiple clients.
Server code:
import socket
import threading
class Server:
def __init__(self):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(('127.0.0.1',1234 ))
print("Waiting for connection")
self.server.listen()
self.loop()
def thread_client(self, conn, addr):
print(addr, ' has connected')
while True:
data = conn.recv(1024)
conn.sendall(data)
def loop(self):
while True:
conn, addr = self.server.accept()
x = threading.Thread(target = self.thread_client, args=(conn, addr,))
x.start()
self.server.close()
s = Server()
Client code:
import socket
class Client:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect()
def connect(self):
try:
self.client.connect(('127.0.0.1', 1234))
except:
print("Something went wrong...")
def send(self, data):
self.client.sendall(data)
return self.client.recv(1024)
c = Client()
print(c.send(b'Hello World'))
print(c.send(b'Hello World'))
When I run py server.py in one terminal this is all I get:
And from the client terminal this is how it looks:
My question is, why am I not recieving a simple print message from the initialization of the server? What does CLOSE_WAIT and FIN_WAIT_2 mean when I run netstat?
The server thread will loop forever until the socket times out resulting in WAIT states on the created sockets as shown in netstat command. Add a check in the server thread to check when data from the client is complete.
Socket Programming HOWTO states:
When a socket.recv returns 0 bytes, it means the other side has closed
(or is in the process of closing) the connection. You will not receive any
more data on this connection.
Server update:
import socket
import threading
class Server:
def __init__(self):
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind(('127.0.0.1', 1234))
print("Waiting for connection")
self.server.listen()
self.loop()
def loop(self):
while True:
conn, addr = self.server.accept()
x = threading.Thread(target=Server.thread_client, args=(conn, addr,))
x.start()
self.server.close()
#staticmethod
def thread_client(conn, addr):
print(addr, ' has connected')
while True:
data = conn.recv(1024)
if len(data) == 0:
break
print("recv:", data)
conn.sendall(data)
conn.close()
s = Server()
For the client, close the socket connect when done.
Client update:
c = Client()
print(c.send(b'Hello World'))
print(c.send(b'Hello World'))
c.client.close() # added

Combine Asyncio Tcp Server and Tornado Web Socket

I have a asycnio tcp server which is connected to 5 tcp client.
import asyncio
class EchoServerClientProtocol(asyncio.Protocol):
def connection_made(self, transport):
peername = transport.get_extra_info('peername')
print('Connection from {}'.format(peername))
self.transport = transport
def data_received(self, data):
message = data.decode()
print('Data received: {!r}'.format(message))
print('Send: {!r}'.format(message))
self.transport.write(data)
print('Close the client socket')
self.transport.close()
loop = asyncio.get_event_loop()
# Each client connection will create a new protocol instance
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
I also have a tornado websocket which is connected to 3 webbrowser.
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
def check_origin(self, origin):
return True
def open(self):
print('New Connection Established')
self.write_message("Connected Server...")
WSHandler.clients.append(self)
def on_message(self, message):
print('Message Received: {}'.format(message))
def on_close(self):
print('Connection Closed...')
WSHandler.clients.remove(self)
del self
#classmethod
def write_to_clients(cls, message):
print("Writing to Clients")
for client in cls.clients:
client.write_message(message)
#classmethod
def write_to_other_clients(cls, self_client, message):
print("Writing to Other clients")
for client in cls.clients:
if self_client != client:
client.write_message(message)
application = tornado.web.Application([
(r'/', WSHandler),
])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Now I want to combine them.Here's what I want to do:
My server will always listen to my clients.
When data arrives from any of them, Program will be posted with Websocket to webbrowser asynchronously.
I did a lot of research, But couldnt reach the success...
You can use the bridge between asyncio and tornado provided by tornado:
# Imports
import asyncio
import tornado.platform
# [...]
# Define Tornado application
class WSHandler(tornado.websocket.WebSocketHandler):
clients = []
# [...]
application = tornado.web.Application([(r'/', WSHandler)])
# Define asyncio server protocol
class EchoServerClientProtocol(asyncio.Protocol):
def data_received(self, data):
WSHandler.write_to_clients(data.decode())
# [...]
# Install asyncio event loop
tornado.platform.asyncio.AsyncIOMainLoop().install()
loop = asyncio.get_event_loop()
# Create tornado HTTP server
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
# Start asyncio TCP server
coro = loop.create_server(EchoServerClientProtocol, '127.0.0.1', 8889)
server = loop.run_until_complete(coro)
# Run forever
loop.run_forever()
# [...]

How to create TCP proxy server with asyncio?

I found these example with TCP client and server on asyncio: tcp server example. But how to connect them to get TCP proxy server which will be receive data and send it to other adress?
You can combine both the TCP client and server examples from the user documentation.
You then need to connect the streams together using this kind of helper:
async def pipe(reader, writer):
try:
while not reader.at_eof():
writer.write(await reader.read(2048))
finally:
writer.close()
Here's a possible client handler:
async def handle_client(local_reader, local_writer):
try:
remote_reader, remote_writer = await asyncio.open_connection(
'127.0.0.1', 8889)
pipe1 = pipe(local_reader, remote_writer)
pipe2 = pipe(remote_reader, local_writer)
await asyncio.gather(pipe1, pipe2)
finally:
local_writer.close()
And the server code:
# Create the server
loop = asyncio.get_event_loop()
coro = asyncio.start_server(handle_client, '127.0.0.1', 8888)
server = loop.run_until_complete(coro)
# Serve requests until Ctrl+C is pressed
print('Serving on {}'.format(server.sockets[0].getsockname()))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

Categories