Quantcast
Channel: Active questions tagged python - Stack Overflow
Viewing all articles
Browse latest Browse all 14040

Tunnel a TCP connection from local system to cloud

$
0
0

I have a custom TCP server on port 7777 and a client that connects to that server and performs some tasks. The server accepts multiple client connections.

./server./client

Since the Server and Client code are already built I can't modify it. This TCP server can only run on the local system but I want to expose this to the internet so that clients outside the network can also connect (I can't open an incoming port on the router).

My solution is to build a tunnel to aws server.

[local: ./server:7777 -> {proxy client 7777 to 8888}] -> (internet) -> [AWS {proxy server: 8888 --> new server: 7777}]

So ./server is running locally on port 7777 port I created a simple Python script that connects to port 7777 and also connects to AWS server 8888 and transfers the data between them. I also do the same at AWS where a proxy server running at 8888 transfers data to a custom server running at 7777. Now I can use my ./client and provide it with the address of the AWS machine it works.

Issue currently is that my solution only works for 1 connection, if two clients are connected there is confusion between proxy server and new server as I am using queue to share data

Server.py -> running on AWS

import socketimport threadingfrom queue import Queueclass TCPServer:    def __init__(self, host, port, to_queue, from_queue):        self.host = host        self.port = port        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        self.server.bind((self.host, self.port))        self.server.listen(5)  # Increased backlog for incoming connections        self.to_queue = to_queue        self.from_queue = from_queue        self.stop_event = threading.Event()  # Event for signaling thread termination    def handle_client_read(self, client_socket, address):        try:            while not self.stop_event.is_set():                data = client_socket.recv(4096)                if not data:                    print(f"handle_client_read Tunnel closed by {address}")                    break                print(f"handle_client_read Tunnel from {address}  {self.host} {self.port}: {data.decode()}")                # Write received data to a queue                self.to_queue.put((data, client_socket))        except Exception as e:            print(f"Error handle_client_read: {e}")            print(f"Closed connection from {address}")    def handle_client_write(self):        try:            while not self.stop_event.is_set():                # Read data from a queue                data, client_socket = self.from_queue.get()                if data:                    # Send the read data to the client                    client_socket.sendall(data)        except Exception as e:            print(f"Error handle_client_write: {e}")    def close(self):        self.stop_event.set()    def start(self):        try:            while not self.stop_event.is_set():                print(f"Server listening on {self.host}:{self.port}")                client_socket, address = self.server.accept()                print(f"Accepted connection from {address}")                thread_read = threading.Thread(target=self.handle_client_read, args=(client_socket, address))                thread_write = threading.Thread(target=self.handle_client_write)                thread_read.start()                thread_write.start()        except Exception as e:            print(f"Error in start: {e}")        finally:            self.close()if __name__ == "__main__":    server_host = '127.0.0.1'    server_port1 = 8888    server_port2 = 7777    tunnel_server_queue = Queue()    server_tunnel_queue = Queue()    server1 = TCPServer(server_host, server_port1, tunnel_server_queue, server_tunnel_queue)    server2 = TCPServer(server_host, server_port2, server_tunnel_queue, tunnel_server_queue)    server_thread1 = threading.Thread(target=server1.start)    server_thread2 = threading.Thread(target=server2.start)    server_thread1.start()    server_thread2.start()    server_thread1.join()    server_thread2.join()

Client.py -> running locally.

import socketimport threadingfrom queue import Queueclass TCPClient:    def __init__(self, host, port, to_queue, from_queue):        self.host = host        self.port = port        self.to_queue = to_queue        self.from_queue = from_queue        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        self.client.connect((self.host, self.port))        print(f"Connected to server at {self.host}:{self.port}")        self.stop_event = threading.Event()  # Event for signaling thread termination    def handle_client_read(self):        try:            while not self.stop_event.is_set():                data = self.client.recv(4096)                if self.stop_event.is_set():                    break                if not data:                    print(f"Received EOF from {self.host}:{self.port}")                    break                print(f"Received: {data.decode()}")                self.to_queue.put(data)        except Exception as e:            print(f"Error receiving data from {self.host}:{self.port}: {e}")        self.close()    def handle_client_write(self):        try:            while not self.stop_event.is_set():                data = self.from_queue.get()                if self.stop_event.is_set():                    break                if data:                    print(f"Sending: {data.decode()}")                    self.client.sendall(data)        except Exception as e:            print(f"Error sending data to {self.host}:{self.port}: {e}")        self.close()    def close(self):        self.stop_event.set()        self.from_queue.put(-1)if __name__ == "__main__":    # base server 7777 -> 8888 -> 7777    local_host = '127.0.0.1'    aws_host = 'address'    server_port1 = 8888    server_port2 = 7777    tunnel_local_queue = Queue()    local_tunnel_queue = Queue()    local_client = TCPClient(local_host, server_port2, local_tunnel_queue, tunnel_local_queue)    tunnel_client = TCPClient(aws_host, server_port1, tunnel_local_queue, local_tunnel_queue)    local_read_thread = threading.Thread(target=local_client.handle_client_read)    local_write_thread = threading.Thread(target=local_client.handle_client_write)    local_read_thread.start()    local_write_thread.start()    tunnel_read_thread = threading.Thread(target=tunnel_client.handle_client_read)    tunnel_write_thread = threading.Thread(target=tunnel_client.handle_client_write)    tunnel_read_thread.start()    tunnel_write_thread.start()    local_read_thread.join()    local_write_thread.join()    tunnel_read_thread.join()    tunnel_write_thread.join()

I am using two queues shared between two servers and two clients to transfer data between them.

I am not sure if this is the right solution, so I am looking for a better solution.

Currently, the issue is here:

    def handle_client_write(self):        try:            while not self.stop_event.is_set():                # Read data from a queue                data, client_socket = self.from_queue.get()                if data:                    # Send the read data to the client                    client_socket.sendall(data)        except Exception as e:            print(f"Error handle_client_write: {e}")

as this thread is called by all clients so when we get data in the queue it is hard to tell which client it belongs to as I can't modify the protocol.


Viewing all articles
Browse latest Browse all 14040

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>