How to create TCP proxy server with asyncio? - python

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()

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

start server socket in a woker and consumer PYTHON ASYNCIO

With a worker I want to run an asyncio server which will be ready to listen.
asyncio.create_task(self.consumer())
await asyncio.gather(
self.obj_Coinbase.manage_connection(), self.obj_server.run()
)
In the coinbase connection i am receiving data i real time and i would like to send this data with my server.
async def run(self):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((self.host, self.port))
server.listen(8)
socket_client, adr = await self.loop.sock_accept(server)
while True:
self.clients_sessions.append(sock)
await self.loop.sock_sendall(self.current_client ,
(json.dumps(self.current_data).encode())) # return Task obj
self.last_data_rcv = self.current_data
it doesnt work when i want to lunch server to distrubte the data
The server blocks the reception of the data from the provider coinbase
thanks

Handle IPV6 adresses in Python asyncio

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()

TCP client reconnect to server if the server is down (using Asyncio)

I am writing a program using asyncio in python where a Client connects to a server, they exchange some messages and the Server closes the connection.
What I also need to implement is a retry mechanism, where in case the server is down the client will keep trying to reconnect every 5 seconds.
Being new in python and with the asyncio concept in general, I need help to understand how to implement that.
Below is a snippet of my code where I start the connection with the server and where I handle it in case of socket closure on server side.
async def main():
# Get a reference to the event loop as we plan to use
# low-level APIs.
format = "%(asctime)s: %(message)s"
logging.basicConfig(format=format, level=logging.INFO,
datefmt="%H:%M:%S")
executor1 = concurrent.futures.ThreadPoolExecutor(max_workers=2)
future1 = executor1.submit(init_thread)
loop = asyncio.get_running_loop()
on_con_lost = loop.create_future()
message = future1.result()
message = struct.pack(">I", len(message)) + bytes(message, "utf-8")
transport, protocol = await loop.create_connection(
lambda: EchoClientProtocol(message, on_con_lost),
'127.0.0.1', 9000)
# Wait until the protocol signals that the connection
# is lost and close the transport.
try:
await on_con_lost
finally:
transport.close()
asyncio.run(main())

python XMLRPC + socket relay server with "kill client"

I'm trying to make a server with Python to relay traffic from listening ports to remote hosts. I'll call the listening port <--> remote host a proxy, which might be localhost:54321 <--> somehost:2001.
I need the following functionality from another thread running a XMLRPC server:
Add a new proxy
Kill a proxy
Disconnect the client from a proxy listening port.
This is rather trivial to implement with threads. Here's what I came up with:
import logging
import threading
import socket
class ProxyThread(threading.Thread):
""" Thread that serves as a transport proxy """
def __init__(self, server, client):
super(ProxyThread, self).__init__()
self.server = server # (host, port)
self.client = client # listening socket
self.kill_thread = threading.Event()
self.kill_client = threading.Event()
def connect_server(self):
try: # make connection to server
server = socket.create_connection(self.server, timeout=2)
except Exception as e:
return None
return server
def connect_client(self):
try: # accept connection from client
self.client.settimeout(1)
client, saddr = self.client.accept()
except socket.timeout:
return None
return client
def run(self):
client, server = None, None
def close():
if client:
client.close()
if server:
server.close()
return None, None
while not self.kill_thread.isSet():
if not server:
server = self.connect_server()
if not server:
time.sleep(2) # wait before retrying
continue
if not client:
client = self.connect_client()
if not client:
continue
while not (self.kill_client.isSet() or self.kill_thread.isSet()):
# read loop 0.1 timeout to check kill_client event
r, w, d = select.select([client, server], [], [], 0.1)
if client in r:
read = client.recv(1024)
if not read: # disconnected
break
server.sendall(read)
if server in r:
read = server.recv(1024)
if not read: # disconnected
break
client.sendall(read)
# close sockets and reset
client, server = close()
self.kill_client.clear()
# end of thread
close()
self.client.close()
Then from the XMLRPC thread,
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("", 0))
sock.listen(1)
proxy = ProxyThread(sock, ('somehost', 2001))
proxy.start()
# later ...
proxy.kill_client.set()
This works but it is pretty inefficient and introduces quite a bit of latency. Further compounding the issue is that this server will be hosting up to hundreds of concurrent proxies, and with threading this becomes a CPU hog and latency is unacceptable.
I'm looking into asynchronous frameworks such as twisted and asyncio, but I can't figure out how I would be able to add and control running proxies from another thread (the XMLRPC server). Can anyone please help guide me in the right direction?

Categories