0

Below I have two scripts that work when I bind the server.py to my computers IPV4 address and connect the client.py to that same address. The next step I'm trying to take is the ability to use this socket across different networks. I thought that it would be as simple as changing the value of SERVER to my public IP address (which can be found by clicking this link). When I make that change, I get this error upon running server.py:

Traceback (most recent call last):
  File "C:\Users\gmbra\Downloads\Python Programs\Concepts\Sockets\server.py", line 13, in <module>
    server.bind(ADDRESS)
OSError: [WinError 10049] The requested address is not valid in its context

server.py

import socket
import threading

PORT = 5050
# SERVER = '192.168.0.30'
SERVER = socket.gethostbyname(socket.gethostname())  # Change this to the public IP address to allow access across multiple networks
ADDRESS = (SERVER, PORT)
HEADER = 64  # The number of bytes expected to get from the client
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "!DISCONNECT"

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # AF_INET is the type of addresses we are looking for
server.bind(ADDRESS)


def handle_client(conn, address):
    print(f"[NEW CONNECTION] {address} connected.")

    while True:
        msg_length = conn.recv(HEADER).decode(FORMAT)  # This line also blocks until it receives a message
        if msg_length:
            msg_length = int(msg_length)
            msg = conn.recv(msg_length).decode(FORMAT)
            if msg == DISCONNECT_MESSAGE:
                conn.close()
                break

            print(f'[{address}] {msg}')
            conn.send("Message Received".encode(FORMAT))


def start():
    server.listen()
    print(f'[LISTENING] Server is listening on {SERVER}.')
    while True:
        conn, address = server.accept()  # This line will wait until it finds a connection.
        thread = threading.Thread(target=handle_client, args=(conn, address))
        thread.start()
        print(f"[ACTIVE CONNECTIONS] {threading.active_count() - 1}.")


print("[STARTING] Server is starting...")
start()

client.py

import socket

HEADER = 64
PORT = 5050
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = '!DISCONNECT'
SERVER = "192.168.0.30"
ADDRESS = (SERVER, PORT)

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDRESS)


# The pickle module could be used to send objects instead of strings.
def send(msg):
    message = msg.encode(FORMAT)
    # For some reason we have to send a byte string first with the integer size of the message, concatenated with spaces
    # until it hits the length of the header.
    send_length = str(len(message)).encode(FORMAT)
    send_length += b' '*(HEADER - len(send_length))
    client.send(send_length)
    client.send(message)
    print(client.recv(2048).decode(FORMAT))


while True:
    message_ = input('Message: ')
    send(message_)
    if message_ == "!DISCONNECT":
        break

What must I do to make this work across different networks?

3
  • 1
    set SERVER to '' in server.py to indicate that the port should be accessible from any of the server's networks. (note that if your PC is behind a firewall, the firewall will still block incoming TCP connection as usual, though) Commented Aug 18, 2021 at 1:39
  • @JeremyFriesner Then what should I connect client.py to? Commented Aug 18, 2021 at 1:52
  • 1
    @GabeMorris the router's public IP. But the router has to configured to forward connection from the WAN to the LAN. Commented Aug 18, 2021 at 1:56

1 Answer 1

3

The server socket can bind only to an IP that is local to the machine it is running on (or, to the wildcard IP 0.0.0.0 to bind to all available local IPs). Clients running on the same network can connect to the server via any LAN IP/Port the server is bound to.

However, when the server machine is not directly connected to the Internet, but is running behind a router/proxy, the server socket cannot bind to the network's public IP. So, for what you are attempting, you need to bind the server socket to its local LAN IP (or wildcard) and Port, and then configure the network router to port-forward inbound connections from its public WAN IP/Port to the server's private LAN IP/Port. Then, clients running on other networks can connect to your public WAN IP/Port, and then be forwarded to the server.

If the router supports UPnP (Universal Play-by-play) and it is enabled, the server code can programmably setup the port forwarding rules dynamically. Otherwise, the rules need to be configured manually in the router's configuration by an admin.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! Sadly, I won't be able to configure the current network to forward any connections because I don't have administrative access. If I were to have access to this network, would I type in the router's IP address into my browser and configure the settings there?
@GabeMorris that depends on the router's software and config. Most routers can be configured by browser, but only when connected to on the LAN side. Using the LAN IP will work, sometimes a domain name works, too (ie, I have an Asus router, and can enter router.asus.com in my browser). Typically, access can also be opened on the WAN side too, if remote access is needed. And some routers can also be configured by mobile app over Wifi.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.