How to connect a socket to another computer's socket through Internet - python

I recently have some difficulties to connect a socket to another computer's socket through Internet, an image is worth a thousand words:
Computer A is running this "listener.py" script:
import socket
PORT = 50007
BUFFER = 2048
HOST = ''
if __name__ == '__main__':
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(BUFFER)
if not data: break
conn.sendall(data)
Computer B is running this "sender.py" script:
import socket
HOST = '101.81.83.169' # The remote host
PORT = 50007 # The same port as used by the server
if __name__ == '__main__':
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b'Hello, world')
So first of all, I run the "listener" script of the computer A. Then, I run the "sender" script of the computer B. However, when I execute the "sender" script, I received a error message which explains me that I am not authorized to connect to this remote address.
So I would like to know how can I connect a socket to another socket through internet without changing the router configurations.
Thank you very much for your help.
Edit: Here the error message (I didn't execute the same script for some reasons, but it's the same error message)
sock.connect(('101.81.83.169',50007)) Traceback (most recent call last): File "<stdin>", line 1, in
<module> File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 224, in
meth return getattr(self._sock,name)(*args) socket.error: [Errno 61] Connection refused

So I would like to know how can I connect a socket to another socket through internet without changing the router configurations.
You can't. The public IP address belongs to your router. Your server isn't listening in the router, it is listening in some host behind the router. You have to open that port in your router and forward it to the host your listener is running in: whatever that means in your particular router. Otherwise the router will refuse the connection, as it doesn't have anything listening at that port.

Computer B can't directly connect to computer A since it has an IP address which is not reachable from the outside. You need to set up a port forwarding rule in the 101.81.83.169 router that redirects incoming connection requests for port 50007 to IP address 192.168.0.4.
However, since you say that you are seeking a solution without changing router configurations, you need something different.
In this case, you could setup an intermediate server running on the public Internet that both computers can then connect to and serves as an intermediate tunneling platform between them. Solutions for this already exist, for example have a look at ngrok, which has Python bindings available.

From the book "Computer Networking: A Top-Down Approach", there is a part which is very interesting on page 149 about how Bittorents work:
Each torrent has an infrastructure node called a tracker. When a peer joins a torrent, it registers itself with the tracker and periodically informs the tracker that it is still in the torrent. In this manner, the tracker keeps track of the peers that are participating in the torrent. A given torrent may have fewer than ten or more than a thousand peers participating at any instant of time. Alice, joins the torrent, the tracker randomly selects a subset of peers (for concreteness, say 50) from the set of participating peers, and sends the IP addresses of these 50 peers to Alice. Possessing this list of peers, Alice attempts to establish concurrent TCP connections with all the peers on this list. Let’s call all the peers with which Alice succeeds in establishing a TCP connection “neighboring peers.
So:
- Step 1: Alice connects to the tracker, the tracker gives to Alice the ip addresses of Bob and Mick.
- Step 2:Alice receives the ip addresses of Bob and Mick, then she can try to establish TCP/IP connections for downloading the file.
I don't remember having to set up any router configuration when I wanted to download files from Bittorent.
So what am I missing?

Related

Connection time out on sockets

Good day everyone! I'm still doing research on this so please pardon if I make any mistake. I'm currently working on a small project that need socket connection between 2 device, problem is, when ever I used the client and the server on the same device, it worked out okay. But when I moved the client into a different device, then started the process again(same LAN connection), it just gave me the time out error [WinError 10060]. Here is my code:
Server side:
HOST = '10.0.0.32'
PORT = 44132
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((HOST, PORT))
server.listen()
client, address = server.accept()
Client side:
HOST = '10.0.0.32'
PORT = 44132
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((HOST, PORT))
I have tried disabling the Firewall and restart computer, changing port or trying to check in cmd if server is really Listening or not, is there anything that I'm missing here? Thank you.
The full error report is: 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
edit:
Here is also my port listening on 44132 using netstat:
Proto Local Address Foreign Address State
TCP 0.0.0.0:44132 0.0.0.0:* LISTENING
edit2: Another update on my end, I've tried turning off the firewall on target machine and ping it, the ping now went through successfully but the client and server still refused to reconnect and continue on timing out. Could it be that there is another firewall between my 2 devices and are implemented by the router to prevent the connection taking place?
Probably you are using the wrong ip address, my advice is to use the command arp -a to check if the server's ip is correct (if you have access to the router you could check there otherwise).
Moreover, be aware when you use socket.gethostbyname(socket.gethostname()), take a look here Python socket.gethostname

Win Error 10061 No connection could be made because the target machine actively refused it

I have been experimenting with the socket library for python. I made a simple program for the server and client where the client can message the server.
Here is my code for the server:
import socket
print("Host")
socket_main = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_main.bind(('127.0.0.1', 9999))
socket_main.listen(1)
conn, addr = socket_main.accept()
while True:
data = conn.recv(1204).decode()
print(data)
conn.close()
Here is my code for the client
import socket
print("Client")
socket_main = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_main.connect(('127.0.0.1', 9999))
while True:
message = input(": ")
socket_main.send(message.encode())
socket_main.close()
When I run these programs in two different terminals on one computer it works just fine, but when I try to run the server and client on different computers I get an error on the clients end saying, "No connection could be made because the target machine actively refused it".
I have tried changing the port multiple times but it didn't help. I have looked through a lot of other forums and I haven't been able to fix this problem for a while now so I decided to ask here.
when I try to run the server and client on different computers I get an error on the clients end
That is because you are using127.0.0.1 on both sides. That is the localhost loopback IP address. It works when the client and server are on the same machine, but it is not routable on the LAN network.
You need to:
change the server to listen on either 0.0.0.0 (to listen on all installed network interfaces), or its actual LAN IP address (just the network interface attached to the LAN).
change the client to connect to the server's hostname or IP address on the LAN.
I have tried changing the port multiple times but it didn't help
The problem is nit with the port, but with the IP address.

Peer to peer socket communication without port forwarding

First of all I am not talking about a tcp or udp or socket implemented in a vps or server
My question is just like client to client socket communication.
Imagine listening at your home pc with a tcp socket. You can connect to this from home inter network anyway. But suppose someone wants to connect to it via the internet. Then you can create a forwarding rule on the router and bring it to working condition. Then the router knows that if an incoming connection comes from a port, the connection will be forwarded to the device in the relevant inter network.
But the ISP I use does not support port forwarding.
I thought these were not impossible because of the team-viewer software. Because when I was connected to a friend in team-viewer, I opened the wire-shark and reviewed it.
Then I saw that the data packet is exchanged peer to peer. Because the destination source addresses were my ip and friend's ip
This means that the video data is exchanged without the participation of an additional server
I highlighted the team-viewer connection.
61.245.175.81 is my friend's public IP. 192.168.1.130 is my internal IP
I want to do the same
Here is my simple socket code. This does not work through the internet because there is no router forwarding rule. I am very new to socket and networking side
Sever
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(('', 12000))
while True:
message, address = server_socket.recvfrom(1024)
message = repr(message)
print("Connected from -> " + str(address) )
print("Received data -> " + message)
reply = b"Hi from server :) "
server_socket.sendto(reply, address)
Client
import time , datetime
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.settimeout(1.0)
message = bytes(str(datetime.datetime.now()),'utf-8')
addr = ("192.168.1.130", 12000)
client_socket.sendto(message, addr)
try:
data, server = client_socket.recvfrom(1024)
print( repr(data) )
except: #socket.timeout:
print('REQUEST TIMED OUT')
Can anyone give an explanation for my question
Pretty sure they do it using UDP hole punching, you'd need to do something similar to implement this.
In a nutshell two clients behind NAT (which is what your router is doing) can use a third server acting as a sort of mediator to establish a connection.

Selecting random port on a remote host

I want to select a random high port on a remote linux machine and use it for my application. On my localhost, I can bind to port 0 and get a random high port, but this does not work if I give a remote host.
The code is as follows:
host = "remote_host"
def get_open_port():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
Error:
Traceback (most recent call last):
File "server.py", line 25, in <module>
port = get_open_port()
File "server.py", line 11, in get_open_port
s.bind((host,0))
File "<string>", line 1, in bind
Well I guess you are bit confused with the client-server communication. Before getting to the solution of your problem lets first revisit the client-server communication process. Normally it is the client who makes/initiates the connection request (simply a connection) to the server. The client makes a request to the server on a remote port which is listening for incoming connections. This remote port should be open on the server side and should be waiting for incoming connections. For eg: If you want to connect to a remote server on the remote port number 15200, then it is mandatory that you should open the port number 15200 on the server side and it should be listening for any incoming connections/requests. Also, the client will know this in advance to which remote port it should make a request for a connection!
Lets understand some more facts before getting to the one of the possible solution to your problem. First lets understand the server side.
Server side: You are trying the server to use any random port for accepting incoming connections from a client. It will surely work as you are binding port number 0 in your server code as s.bind((host,0)). When you bind the port number 0 then your server (actually the OS which is running the server script) will use any random high port number for accepting the remote connections which will be usually greater than 1023. You can test this by following code snippet. Run the following code snippet and you may notice that the server is opening random high port numbers.
import socket
host = "127.0.0.1"
def get_open_port():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,0))
s.listen(1)
port = s.getsockname()[1]
s.close()
return port
for i in range(0,5):
print "Opening port no. %s"%get_open_port()
On executing the above code you'll shall see that a random port number is being selected by the server code to accept incoming connections every time. But it is also closing it after wards using s.close(). In my case the output was as below (You may get a different set of port numbers):
Opening port no. 60876
Opening port no. 60877
Opening port no. 60878
Opening port no. 60879
Opening port no. 60880
So, I guess now you understood the server part. Lets discuss the client side now.
Client side: As mentioned earlier that a client needs to know the remote server port to which it needs to connect. A typical client code looks as given below:
import socket
host = "127.0.0.1"
port = 60880
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
In the above code snippet this line s.connect((host, port)) you need to mention the host the remote host name or IP and port the remote port to which you want to connect to.
So it means that client should know the port number in advance! As a result you have to mention the port in your client code. As I have done in my code snippet as port = 60880.
Now coming to your question: As you already noticed from above text that you have to mention the remote server's port number in client code to make a request for a connection. So, you can't expect your client to figure out itself the remote port of the server which is actually listening for incoming request. The client code can't do this by its own.
Solution:
So what if the client code can't figure out by itself the remote port number we'll make it to figure it out! ;) What we know is if you bind the port number 0 on server side then a random port number will be selected which will be greater than 1023. So, it means the random port number will always be greater than 1023. Also, the maximum value of port number is 65535. Ultimately we come to a conclusion that the random port that will used by the server will be any port number in this range 1024 - 65335.
Now all you have to do is in your client code you have to use a range of port numbers to which it should make connection. Because we don't know what remote port is listening on the server side for accepting incoming requests/connection!
Sample code for plying around: I tested these code snippets using my localhost. Here is the server code. Run the server code first then run the client code. Upon executing the server code, it'll display in console/output that what is the random port number opened for accepting incoming request/connections. When a client is connected the server will display a message the Got a client connected along with the IP of the client.
#This is the server script
import socket
host = "127.0.0.1"
def get_open_port():
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind((host,0))
mySocket.listen(1)
port = mySocket.getsockname()[1]
print "Port opened for incoming connections %d"%port
(clientSocket, clientAddress) = mySocket.accept()
print "Got a client: ", clientAddress
clientSocket.close()
mySocket.close()
get_open_port()
Here is a client code sample that will do this crazy stuff. It will try to connect on all the ports from 1024 - 65335 and when it finds any remote port which is listening for incoming connections. It will display a message "Connected to remote port" and then close the socket and continue looking for more open ports until it reaches the last port number 65355.
#This is the client script
import socket
host = "127.0.0.1"
def startConn():
for port in range(1024,65336):
try:
myClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "Trying remote port: ",port
myClientSocket.connect((host,port))
print "Connected to remote port: ",port
myClientSocket.close()
except socket.error as msg:
myClientSocket.close()
continue
startConn()
This is just a sample code, I am intentionally closing the sockets after a successful is established. You can do something else what you ever you prefer. I hope now it is quite clear to you regarding server-client communication.

Making Python sockets visible for outside world?

i already have a post which is quite similiar, but i am getting more and more frustrated because it seems nothing is wrong with my network setup. Other software can be seen from the outside (netcat listen servers etc.) but not my scripts.. How can this be??
Note: It works on LAN but not over the internet.
Server:
import socket
host = ''
port = 80001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(1)
print 'Listening..'
conn, addr = s.accept()
print 'is up and running.'
print addr, 'connected.'
s.close()
print 'shut down.'
Client:
import socket
host = '80.xxx.xxx.xxx'
port = 80001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
s.close()
Somebody please help me.
Any help is greatly appreciated.
Jake
Edited again to add:
I think you may be missing some basics on socket communication. In order for sockets to work, you need to ensure that the sockets on both your client and server will meet. With your latest revision, your server is now bound to port 63001, but on the local loopback adapter: 127.0.0.1
Computers have multiple network adapters, at least 2: one is the local loopback, which allows you to make network connections to the same machine in a fast, performant manner (for testing, ipc etc), and a network adapter that lets you connect to an actual network. Many computers may have many more adapters (virtual adapters for vlans, wireless vs wired adapters etc), but they will have at least 2.
So in your server application, you need to instruct it to bind the socket to the proper network adapter.
host = ''
port = 63001
bind(host,port)
What this does in python is binds the socket to the loopback adapter (or 127.0.0.1/localhost).
In your client application you have:
host = '80.xxx.xxx.xxx'
port = 63001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
Now what your client attempts to do is to connect to a socket to port 63001 on 80.xxx.xxx.xxx (which is your wireless internet adapter).
Since your server is listening on your loopback adapter, and your client is trying to connect on your wireless adapter, it's failing, because the two ends don't meet.
So you have two solutions here:
Change the client to connect to localhost by host = 127.0.0.1
Change the server to bind to your internet adapter by changing host = 80.xxx.xxx.xxx
Now the first solution, using localhost, will only work when your server and client are on the same machine. Localhost always points back to itself (hence loopback), no matter what machine you try. So if/when you decide to take your client/server to the internet, you will have to bind to a network adapter that is on the internet.
Edited to add:**
Okay with your latest revision it still won't work because 65535 is the largest post available.
Answer below was to the original revision of the question.
In your code posted, you're listening (bound) on port 63001, but your client application is trying to connect to port 80. Thats why your client can't talk to your server. Your client needs to connect using port 63001 not port 80.
Also, unless you're running an HTTP server (or your python server will handle HTTP requests), you really shouldn't bind to port 80.
In your client code change:
import socket
host = '80.xxx.xxx.xxx'
port = 63001
And in your Server Code:
import socket
host = ''
port = 63001
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostbyname(socket.gethostname()), port ))
In your server script you have port = 80, but you don't ever use it. It looks like the server is listening on 63001. And the client is connecting to 80.
If you're going to use 80, make sure you don't have an http server trying to use the port at the same time as well.

Categories

Resources