The problem
I am trying to use the SocketServer that ships with Python but I have some issues in the handshake phase. The handshake works fine as long as I use localhost or 127.0.0.1. However when I put the IP of my eth0 card it just won't handshake. I test the official example code found here:
import SocketServer
class MyTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
print "{} wrote:".format(self.client_address[0])
print self.data
self.request.sendall(self.data.upper())
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server.serve_forever()
Terminal snippet:
manos#box:~$ netcat 10.2.203.26 9999
manos#box:~$
manos#box:~$ netcat localhost 9999
test
As you see in the snippet, trying to connect to 10.2.293.26 which is the IP of my network card doesn't work. As soon as I try to connect to localhost, it works fine!
On Wireshark I get a [RST, ACK] after the first SYN being sent from the client to the server (in the initial handshake phase).
Works fine with telnet
My first guess was that this was a router resetting the connection. However that is not the case since I can telnet fine:
Terminal 1:
manos#box:~/tmp/test$ netcat -l 9999
(waiting)
test
Terminal 2:
manos#box:~$ netcat 10.2.203.26 9999
test
You're binding to localhost, which doesn't allow specifying the IP address/es of the machine's interface/s as the destination on the connecting host.
You should specify 0.0.0.0 or the empty string as the machine's address in the bind operation (the HOST argument in your example) in order to allow the remote host to specify any of the machine's IP addresses as the destination.
For more information about the difference between localhost, 127.0.0.1 and 0.0.0.0 refer to this answer or to this one.
Related
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)
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.
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.
first apologies if this is a v stupid question - forgive me - but i cannot make heads or tails for this scenario.
I created a python server script (basic socket script) that binds localhost and port 9999 on my PC.
Next on my virtualbox (Linux mint) I run a simple telnet connection.
This is whats confusing the heck out of me - on my 'server'
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((_host, _port))
s.listen(3)
print (f'Listening on {_host} and port {_port}')
_conn, _addr =s.accept()
print(f'Server IP/Port {_conn.getsockname()} Established')
print(f'Client IP/Port {_addr} Established')
I can see that the python script is binding to port 9999
And when i run telnet from linuxmint I can see that the telnet session is connecting to the server
But i cannot co-rrelate the port that is on linuxmint vs what i see on my windows 10 python script
So ...
This is the output from the python code snippet :
Listening on and port 9999
Server IP/Port ('192.xxx.xxx.xxx', 9999) Established
Client IP/Port ('192.xxx.xxx.xxx', 53016) Established
Listening on and port 9999
BUT
Confirming this on windows netstat :
Established 9999 192.xxx.xxx.xxx 53016 192.xxx.xxx.xxx
However; on the virtualhost when I do
netstat-tp
I get ...
Local Address :55638
Question I have is what is 55638 and why dont i see 53016 as a port on linuxmint ??
Please can you help - i tried netsat -a | grep 53016 (nothing) but netstat -a | grep 55638 gives me the telnet hit.
Please can you help.
Thanks
I'm trying to create a Python program that will listen on a socket. I'm using Windows 7 with Python 2.7. Whatever I do, the socket seems to be accessible from the local machine but not from elsewhere on the network.
I've got the following code:
from werkzeug.wrappers import Request, Response
#Request.application
def application(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
# Using empty string or the machine's real IP address here
# gives the same problem
run_simple('0.0.0.0', 4000, application)
If I connect from the local machine I see the response fine. If I execute
$ curl 'http://192.168.1.1:4000/'
from another (linux) box on the network, the curl hangs for a long time before timing out. Wireshark shows that I receive a SYN packet to port 4000 but don't see it ACKed.
I've tried making sure packets to this port are allowed through the firewall (the fact that I see the SYNs in Wireshark suggests this is not the problem). I've tried setting Python to run as administrator (and I've checked that ctypes.windll.shell32.IsUserAnAdmin() returns true). This isn't just Werkzeug, I've tried with SocketServer from the Python standard library as well.
Running Windows Apache on the same port works fine from across the network, which suggests there's no problem with the network or firewall or with my curl request.
netstat -an shows:
TCP 0.0.0.0:4000 0.0.0.0:0 LISTENING
Edit: I've tried with the following minimal code. On the server side (Windows 7):
import socket
s = socket.socket()
s.bind(('', 8080))
s.listen(1)
remotesock, addr = s.accept()
And on the linux client:
import socket
s = socket.socket()
s.connect('192.168.1.1', 8080)
This hangs until timeout, as with the curl.
I believe the problem is due to your address binding. Python does not allow sockets bound to localhost (or 0.0.0.0) to be visible from the outside world. Change the binding to your actual IP Address.
EDIT: Showing example code
Change your code to this
import socket
s = socket.socket()
s.bind(('192.168.1.1', 8080)) # assumes your machine's IP address is 192.168.1.1
s.listen(1)
remotesock, addr = s.accept()