Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python Socket server with real ip address

Tags:

python

sockets

ip

I am playing with my python server, but I'm through with using localhost and I want to go over the internet. My code thus-far is:

import socket
import threading
import socketserver

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.current_thread()
        response = "{}: {}".format(cur_thread.name, data)
        self.request.sendall(b'worked') 

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print("Received: {}".format(response))
    finally:
        sock.close()

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "0.0.0.0", 9001

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print("Server loop running in thread:", server_thread.name)
    ip = '12.34.56.789' #Not my real ip address This is just to hide my ip
    print(ip, PORT)

    client(ip, PORT, b'Hello World 1')
    #client(ip, port, b'Hello World 2')
    #client(ip, port, b'Hello World 3')

    server.shutdown()

When I run this i get the error:

Server loop running in thread: Thread-1
12.34.56.789 9001
Traceback (most recent call last):
  File "C:/Python32/serverTesty.py", line 43, in <module>
    client(ip, PORT, b'Hello World 1')
  File "C:/Python32/serverTesty.py", line 18, in client
    sock.connect((ip, port))
socket.error: [Errno 10061] No connection could be made because the target machine actively refused it

I know the port works because when I use canyouseeme.org on port 9001 when my program is running it says its active and working. So I think I just have my connection wrong somewhere.

like image 213
user1642826 Avatar asked Sep 27 '12 23:09

user1642826


1 Answers

ip = '12.34.56.789' #Not my real ip address, its the one i got from whatismyip.org

The first problem is that '12.34.56.789' isn't a valid IP address at all. Each component has to fit in 8 bits (0-255); 789 is impossible. But I assume that isn't the actual code you're running, because the output shows 12.45.29.122.

The second problem is that you're using an address that isn't your real address.

Your machine presumably has an internal IP address, that can only be accessed from your LAN. Then, your router has an external IP address. The router uses a technique called Network Address Translation to let each machine on your LAN pretend that external address belongs to them, when they're acting as clients (which is why whatismyip.org shows you that address). But that doesn't work when they're acting as servers.

If you think about it, there's really no way it could work. If you make an outbound connection, and someone replies, the router knows that the reply should go to your machine. But if someone just comes along and talks to the router out of the blue, how could it know which machine to send the connection to?

If you're trying to connect from inside the same LAN, there's a very easy solution: use the server's real internal address, not the router's external address.

If you need to connect from outside, you can't, without some extra work. There are four ways around this:

  1. Give your machine a real publicly-addressable IP address (e.g., by putting it on the router's DMZ). This is generally not even an option for home users, and it's a bad option for people who don't know what they're doing (unless you want your machine to be part of someone's botnet by lunchtime).

  2. Set up static port forwarding in your router's configuration. This is different for each router, but the idea is that you tell it "if someone comes looking for port 9001, always send them to machine 192.168.1.64".

  3. Use UPnP to set up port forwarding dynamically.

  4. Set up a NAT hole punching.

Options 3 and 4 are more complex, and I think option 2 is the one you want, so I won't explain them.

On top of all that:

HOST, PORT = "192.168.1.64", 9001

server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)

You've told the server explicitly "listen on 192.168.1.64". Even if you put your server machine on the DMZ, so it had addresses 192.168.1.64 and 12.45.29.122, your program is only listening for connections on the first one, so nobody would be able to reach it using the second. If you want to listen on all addresses, use 0.0.0.0.

In the edited version, you're now listening on 0.0.0.0, and connecting to the router's public IP, and you claim to have set up port forwarding on the router, and you're still getting the exact same error.

If that's all correct, there are three obvious things that could be going wrong:

  1. You're not actually port forwarding; something is wrong with the setup.
  2. You're not actually listening on 0.0.0.0:9001.
  3. You've got a firewall blocking the connection.

There are a few tests you can do to narrow things down.

  1. Open two terminals. In one, type nc -kl 9001. In the other, type nc 12.34.56.78 9001. They should connect up, so anything you type into one window appears in the other (maybe only after you hit Return). If that works, the port forwarding is working, and there's no firewall problem, so it's a problem in your code.

  2. If that didn't work, please post exactly what you saw in each window. Then Ctrl-C the second nc, and type nc 192.168.1.64 9001. If that now works, either the port forwarding isn't set up right, unless you have a clever firewall that allows same-host (or same-interface) connections but not remote connections.

  3. If neither one worked, it's probably a firewall problem. (Unless you're wrong about your IP addresses or something.) You can probably find logs somewhere, but without knowing what platform you're on and what firewall you're using it's hard to offer much help. (Also, that's probably a problem for a different site than SO.)

If you're on Windows, or some linux distros, you need to get a copy of nc (netcat) from somewhere; on most linux distros, and Mac, it should be built in. Also, GNU, BSD, and Hobbit nc are slightly different, so if nc -kl 6000 gives you an error, you might have to read the man page or --help. (If I remember right, Hobbit nc requires -l -p6000, BSD requires -l 6000, GNU allows either.)

Or you may want ncat, a re-implementation of netcat that I know can handle the syntax I used above, and has a single-file static executable for Windows.

If you can't get started with nc, at least try changing your code to connect to 192.168.1.64 instead of 12.34.56.78. If that fixes the problem, at least you'll know it's either port forwarding or a firewall that allows same-host/interface connections but not remote.

like image 52
abarnert Avatar answered Nov 15 '22 08:11

abarnert