Create TCP Server accessible on remote networks - python

A project I am working on has an Android app as a front-end and a Python program that would be used as the back-end.
I want to send data from the Android app (primarily images) to the Python program, do some processing and send the result back to the Android app.
I have found numerous tutorials that suggest using the socket module in python to create the server side, but all tutorials show the server on local network only (For testing purposes I created the client side also in Python, but it would be converted to Java later on)
The server code:
from requests import get
import socket
public_ip = get('https://api.ipify.org').text
print('My public IP address is: {}'.format(public_ip))
# getting the hostname by socket.gethostname() method
hostname = socket.gethostname()
# getting the IP address using socket.gethostbyname() method
local_ip = socket.gethostbyname(hostname)
# printing the hostname and ip_address
print(f"Hostname: {hostname}")
print(f"IP Address: {local_ip}")
#
HOST = local_ip
PORT = 80 # Port to listen on (non-privileged ports are > 1023)
with socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024).decode('utf-8')
if not data:
break
conn.sendall(data.encode('utf-8'))
The client code:
import socket
HOST = '…' # I modify it to the server's public IP address, as printed from the server code
PORT = 80 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
with socket.create_connection((HOST, PORT)) as s:
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
Using the code above, if I try using any port other than 80 I get ConnectionRefusedError: [Errno 111] Connection refused. And for port 80, I get TimeoutError: [Errno 110] Connection timed out.
In both cases, I try to connect from a device on another network.
I tried to use the ping command in Windows CMD to check the connection to the server, and I get 'connection refused message'.
I understand that the Firewall is what probably blocks the connection, but I don't know how to bypass it. I added a new rule in the Inbound Rules section (as suggested on other websites) but for no avail… The results were the same.
How can I make the connection between remote devices on different networks?
Thanks in advance ☺

In order to connect to your server using a TCP socket connection, you need to make sure your server can listen on a port on a publically available IP address.
If the External IP address is assigned to your computer directly,
and if you run the server code on that computer, then the TCP port opened by the server code should be available on the internet.
However, IP addresses are often assigned to a modem/router in home networks,
instead of assigning them to any connected device directly.
To find out if your External IP address is assigned to the computer directly you can use tools that your OS support (eg. ipconfig on windows). If you can see the IP address returned by api.ipify.org, then it means your computer is connected directly. You can change your code to connect using publically exposed IP:
HOST = public_ip
If this is successful means your computer is assigned an external address directly. Which is highly unlikely.
There are several workarounds for this problem though:
1) Configure your router to forward port
Configure your router to forward all connections to it's external TCP port, to an internal host in your network which is assigned to your computer. Please find instructions how it is done for your router.
2) Setup a remote proxy
If you don't have permission to change your router settings you can set up a remote proxy listening on the TCP port. While there is a number of ways of doing this, very popular is to set up a remote SSH tunnel, for that you need to have a server with SSH access and an external IP. Run this command:
ssh -R 80:localhost:8080 root#your-ssh-server-host
You can also use a third-party service that exposes your private host on the internet like:
Ngrok (Commercial, with free plans)
Localtunnel (Open Source, can be self-hosted)

Related

TCP Socket not connecting [WinError 10060] - Python

I'm making a chat app using sockets in python, but when I try to connect from a different computer then it says:
C:\Users\James\OneDrive\Documents\Python\Projects\Gui Chat\client.pyw
[WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
This is the server code for the socket:
host = socket.gethostbyname(hostname)
port = 55555
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
print(f"IP: {server.getsockname()[0]}\nPORT: {server.getsockname()[1]}")
server.listen()
I also have a while True loop accepting all requests:
while True:
client, address = server.accept()
print(f"Connected with {str(address)}")
On the client end this is the socket code:
IP = simpledialog.askstring("IP", "Enter IP address", parent=root) # "192.168.1.252" # input("Enter IP: ")
nickname = simpledialog.askstring("Nickname", "Choose a nickname", parent=root)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
client.connect((IP, 55555))
except Exception as e:
print(e)
The programme asks for the IP address each time, and when I put in the correct IP for the server computer, it comes up with the error above. It works if I try to connect from the same computer, and they are both on the same network. It was working recently, and now it has just stopped working.
UPDATE:
I have set the server ip to 0.0.0.0, I have set up a port forwarding rule, I have checked the firewall and allowed incoming and outgoing connections, and I have run nmap with these results:
Code issues
First try binding server on localhost or 127.0.0.1.
FireWall/Ports issues
Check if your computer's default computer/antivurus
firewall (where server is hosted) allow connections
on your port 55555.
And if computer with client is outside your home network
point to router public IP address and make sure you have
port forwarding setup on router.
Address issues
Are you sure that IP you are writing in client is correct.
Go to your computer with server and check that IP.
Windows:
Go to cmd or Power Shell and type ipconfig, then find
section IPv4 Address and look that address you habe there.
Linux / MacOS
Go to your terminal and type ifconfig -a, and
it should be somewhere there, but I don't have those systems,
so I can't test it for you. If it does't work try to search how to
find that out.

Python on GCE: connection failed because connected host has failed to respond

I've been working on a project that requires a bit of networking between a server (hosted on GCE) and multiple clients. I created a Compute Engine Instance to run a Python script as shown in this video: https://www.youtube.com/watch?v=5OL7fu2R4M8.
Here is my server-side script:
server = socket.gethostbyname(socket.gethostname()) # 10.128.X.XXX which is the Internal IP
print(server)
port = 5555
clients = 0
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((server, port))
s.listen(2)
print("Waiting for connection...")
while True:
conn, addr = s.accept()
print("Connected to: ", addr)
conn.send(str.encode(f"{clients}"))
clients += 1
and here is my client side-script:
class Network:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server = "10.128.0.2"
self.port = 5555
self.addr = (self.server, self.port)
self.id = int(self.connect())
def connect(self):
self.client.connect(self.addr)
return self.client.recv(2048).decode()
network = Network()
print(f"Connected as client {network.id}")
I know this script works because I have tested it with my computer being the server and 1 client, and another computer being the 2nd client. But when I use the GCE as the server, I get this error in the client script:
TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Could this be because I am using the internal IP address and not the external?
After this, I tried changing the firewall settings (added 'python-socket') of the GCE and this is what they look like:
But the error still persists...
As answered by W_B, I tried to run these commands on my VM and got the following outputs:
From your description it's evident it's the connection problem.
First of all you have to check if the firewall rule you created is still there. If it's "too broad" and allows for very wide access then it might be removed automatically even without you knowing it. It's on you'r screenshot but check it again just to be sure.
If it's there select the protocol you're goint to be using (I assume it's TCP) - some protocols are always blocked by default by GCP (you can't change this) so creating a rule with "any protocol" allowed is risky. Also - put one or two target IP's (not all inside this VPC) - this is not a must but improves security of your network.
Second - make sure port 5555 you're trying to connect to is accessible from other computers. You can scan the target host with nmap -p 5554 put.server.ip.here
You can scan it from the Internet or other VM's in the same VPC network.
You should get something like this:
root#localhost:~$ nmap -p 443 192.168.1.6
Starting Nmap 7.70 ( https://nmap.org ) at 2020-06-25 17:12 UTC
Nmap scan report for 192.168.1.6
Host is up (0.00091s latency).
PORT STATE SERVICE
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 0.04 seconds
If you see 5555/tcp filtered freeciv this means that something blocks the port.
Run nmap on the server (I assume you run some version of Linux) and if you don't want to install any non-essencial software you can use sudo netstat -tulpn | grep LISTEN to get a list of open ports (5555 should be on the list).
Also make sure firewall on your server doesn't block this port. You can use iptables for that.

Python socket timing out on other computer. TimeoutError: [WinError 10060]

I'm trying to connect a client to server through python sockets. Clients connect successfully on my computer, but people on other networks cannot connect.
TimeoutError: [WinError 10060]
on the client side after failing to connect. Here is the code for my python scripts.
Server.py
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "0.0.0.0"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
Client.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "##.###.###.###" # server's public ip.
port = 8001
s.connect((host,port))
print("Connected to server.")
s.send(("Client connected").encode())
The ports are different because I can't connect without the local and external ports being different on my router; local being 8000 and external being 8001. If the client is on my computer, the server reveals it's being connected to by the public ip, so it's passing through my router.
Doing nmap -p 8000 -sN -P0 192.168.0.# on my server computer, reveals the port is closed using http-alt. Doing it on my public ip reveals that it's open|filtered using vcom-tunnel, but it's open|filtered on almost every port.
What I have tried:
Port forwarding with local_port=8000 and remote_port=8001. External ip set to my public ip, and my local ip set to my computer ip; 192.168.0.#
Using DMZ Host (Exposed Host) on server-side router.
Enabling and disabling UPNP, WAN Blocking, Ipsec PassThrough & PPTP PassThrough separately on server-side router.
Allowing TCP port 8000, on local and remote through server-side firewall.
Allowing program through firewall on public & private networks on client and server.
Allowing TCP port 8001, on local and remote through client-side firewall.
Binding client ip with socket.bind((client_ip,port)) on client.py
It might be the port I'm using having to do with http-alt/vcom-tunnel, instead of one with upnp.
The problem was setting the external ip on my port forward to my public ip. What ip it was set to, it was only scanning for my ip, which let to only my computer being able to connect to it. I set the external ip to 0.0.0.0, making the port open to all ips.

Python: Connect using sockets via external IP

Today, I have made my very first sockets program - I made a client and a server that message each other (kind of like a chat) using sockets. When using the internal IP as 'host', The connection is established, otherwise using the external IP, no connection is established.
Edit 1:
#Client
s = socket.socket()
host = '123.123.123.123'
port = 9999
s.connect((host, port))
#Server
host = ''
port = 9999
s = socket.socket()
s.bind((host, port))
s.listen(5)
connection, address = s.accept()
How will this work properly with, for example, a laptop? Since your IP changes each time you switch Wifi, how would I be able to create a program that would permanently work with this specific laptop?
I understand that I have to port-forward the specific port to a specific internal machine such as 192.168.0.5. but what if I'm using a laptop and I don't have access to the WIFI router. I wouldn't have access to every router a laptop uses.
I want the code to be permanently compatible.
Use DynDNS.com or NoIP.com portal. You install program on laptop which check your IP frequencly and sends current IP to portal which assigns this IP to your address like "my_laptop.noip.com". Then people can access your laptop using "my_laptop.noip.com" instead of IP address.
You always assign socket to IP of local network card (NIC) like WiFi. You can't assing to external IP. You have to config your router so requests to external IP:port will be send to your local IP:port. Of course Internet Provider routers can block your ports and it will not work.

Python 2.7 Socket connection on 2 different networks?

Title says all. I have a client and a server setup, but they only work with localhost. How can I connect to the socket from a different network?
Client
# Echo client program
import socket
print "Client"
HOST = "localhost" # Symbolic name meaning all available interfaces
PORT = 5001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
while True:
data2 = raw_input()
s.sendall(data2)
Server
# Echo server program
import socket
print "Server"
HOST = "" # Symbolic name meaning all available interfaces
PORT = 5001 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print 'Connected by', addr
while 1:
data = conn.recv(1024)
print data
if data == "Ping":
print "Pong!"
conn.close()
Check your public ip address using online tools like http://whatismyipaddress.com/
Check your local ip address using ipconfig -a in windows ifconfig in linux.
Now if you are behind a dsl router (generally, you are) these addresses are completely different. So you have to tell your router to send whenever a connection attemp received to a TCP port XXXX , forward it to "My Machine" (called Port Forwarding ). Although port forwarding settings are similar in most routers, there is no standard (Generally under NAT / Port Forwarding menu items on your router web configuration interface ). You may have to search instructions for your specific model.It's a good idea to set your computer to use a static ip address before port forwarding.Otherwise, the settings will be invalid if your computer is assigned another IP adress via DHCP.
If port forwarding is successful, now you only have to set your client application to connect to your public ip address. In your specific situation it's HOST = "X.X.X.X" in your client source code. Check if port forwarding works with a socket tester application you downloaded from somewhere. ( Don't test it with your experimental code, use an application you are sure that it's working). All did not work, check out the note below. It's the last resort ,though.
Note : Some ISP's put their clients behind an extra firewall for security. A simple method to detect if this is the situation is , your Wan ip address you see in your router web interface will be different from what you see in online tools like whatsmyip. In this situation no matter what you do , you will not be able to connect. You have to call your ISP and tell them to disable firewall for your connection . You may have some difficulties to explain them what you are talking about :).

Categories