Python network programming(bind to external address) - python

I am a newbie to python, and just few days back I started trying my hands on network programming(I am a newbie there too)
Now I found a neat client server program which was running quite simply on my computer, but when I replaced the local addresses, and told my friend to run the client script, it just wont respond.
My global I.P address : 120.59.XX.XXX
My Ipv4 address as returned by ipconfig : 192.168.1.2 (I am connected to internet through a router)
My gateway address : 192.168.1.1
Port used : 1060 (I tested this port locally and it wasn't in use)
#server.py
import socket
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
MAX = 65535
PORT = 1060
server.bind(('192.168.1.2', PORT))
print 'Listening at', server.getsockname()
while True:
data, address = server.recvfrom(MAX)
print 'The client at', address, 'says', repr(data)
server.sendto('Your data was %d bytes' % len(data), address)
Client Code :
#client.py
import socket
import sys
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
PORT = 1060
MAX = 65536
client.sendto('Hello Server!', ('120.59.XX.XXX', PORT))
data, address = client.recvfrom(MAX)
print 'The server', address, 'says', repr(data)
I started server.py on my computer and told my friend to start client.py, I allowed incoming connections to python through firewall, also I added 1060 port to windows incoming connections list.
Still it is not responding, and I am unable to decipher why(I have a dynamic IP address, but for the current session it remains constant and hence should work, also 1060 is a well known port and shouldn't be a problem right?)

You need to add a port forwarding rule in your router! something like from port 1060 forward to 192.168.1.2 port 1060.

You need a port-forward on the router, which would forward connections to router's external (global) address on port 1060 to your desktop IP 192.168.1.2 port 1060.

Related

Connect to Socket from Outside Local Network

I'm trying to get a socket connection between two different terminals. When they are both on the same computer, or on a different computers on the same network (behind my home router), it works fine.
Here is a minimal example of the code I use. On the client side I enter the IP address I get from running ipconfig on the server, it works with both the IPv4 Address and the Temporary IPv6 Address (changing the corresponding flag of course)
SERVER
import socket
ip_address = ""
ipv6 = False # True
PORT = 12345
STREAM = socket.SOCK_STREAM
if ipv6:
FAMILY = socket.AF_INET6
bind_args = (ip_address, PORT, 0, 0)
else:
FAMILY = socket.AF_INET
bind_args = (ip_address, PORT)
server_socket = socket.socket(FAMILY, STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(bind_args)
server_socket.listen()
unsecured_sock, client_address = server_socket.accept()
print("accepted from", client_address)
CLIENT
import socket
ip_address = "Entered from ipconfig or whatsmyip.com run from server"
ipv6 = False # True
PORT = 12345
STREAM = socket.SOCK_STREAM
if ipv6:
FAMILY = socket.AF_INET6
bind_args = (ip_address, PORT, 0, 0)
else:
FAMILY = socket.AF_INET
bind_args = (ip_address, PORT)
sock = socket.socket(FAMILY, STREAM)
sock.connect(bind_args)
print("Connected!")
The problems arise when I take one of the computers out of the home network. As I don't have two standard networks I can access at the same time, I test this by connecting one of the computers to the internet via either the 4G on my phone or through a VPN. In either case, I then use the IP I get from whatsmyip.com ran from the server. I've tried all combinations of IPv4 vs IPv6 and whether the server or the client is behind my home router. In all cases it fails (note, I don't get a IPv6 address when the server is accessing the internet via 4G on my phone). In fact, I can't even ping or tracert the ip address of the server from the client terminal.
I suspect that I'm doing something very basic wrong, but I don't know what. I suspected it was to do with port forwarding, so I tried the following UPnP script
import upnpy
upnp = upnpy.UPnP()
devices = upnp.discover()
device = upnp.get_igd()
service = device.WANIPConn1
service.AddPortMapping(
NewRemoteHost='',
NewExternalPort=12345,
NewProtocol='TCP',
NewInternalPort=12345,
NewInternalClient='192.168.0.136', # Local server IP
NewEnabled=1,
NewPortMappingDescription='Test port mapping entry from UPnPy.',
NewLeaseDuration=600)
print("added new port mapping")
which runs correctly but makes no difference. Am I right in thinking that this should be a non issue for IPv6 anyway? If it makes a difference, the provider for my internet says that my connection is IPv6 and that I do not have a proper IPv4 public address. Considering I want this to be portable and, eventually distributed, I'd rather avoid it be dependent on specific settings not accessible to the user.
Any pointers for a networking noob are most appreciated

Socket module (python) works but doesn't use specified port number?

I'm using the socket module from Python 3.7 (shouldn't matter, as I tried activating a different Python version from different venv's).
The problem is that I've created a TCP connection listening at port 65432, an arbitrary number that I selected for this simple demo.
server.py looks like the following:
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Non-privileged ports are > 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
client.py is relatively straightforward as it makes a connection with 127.0.0.1:65432.
import socket
HOST = '127.0.0.1' # The server's hostname or IP address
PORT = 65432 # Port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# Send its message and then read the server's reply and prints it
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
Executing server.py to open the port 65432 for listening (in first console) and then executing client.py to send a simple 'hello world' message (in a second console). This is what got printed to the first console:
Connected by ('127.0.0.1', 56051)
So far so good. Port 56051 connecting to port 65432, right? No.
I execute netstat -am (command tool utility to see state of sockets on the host machine) and found this:
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.51495 *.* LISTEN
Instead of 127.0.0.1.65432 as local address, it is using port 51495 instead.
Doing another verification check, this time firing off lsof -i -n:
COMMAND PID FD TYPE DEVICE SIZE/OFF NODE NAME
Code\x20H 51214 37u IPv4 0x1af15eb424ba89f3 0t0 TCP 127.0.0.1:51495 (LISTEN)
Both verifications confirmed that port 51495 is being used instead of 65432 as specified in my server.py and client.py scripts. Any leads or tips? Many thanks in advance!
65432 is the port number of your server socket, not your client socket. As the client end is not attached with any specific port number, it will be dynamically allocated with port number, every time you run the client code.
As far as I understood, you mentioned -
Connected by ('127.0.0.1', 56051)
is shown on the first console which is your server console. so this port number is port number of client socket. not the server socket.
In the server code, you are using, s.accept(), this function returns the connection temporary id and the address of the client which made the request. same thing you are trying to print in the code.
As #ottomeister pointed out, the process name was the first giveaway. The process name should have been Python but it showed VS Code instead, which is indicative that the port 51495 is opened by the VS Code process and has nothing to do with our socket module code.
The way the context manager was setup means that the connection will be closed the moment the last line (in this case, socket.sendall()) is executed. So the server socket is not active anymore.
I run netstat after the client socket has connected, by this point the server port is closed.
When I monitor the ports status while the server port is open (before the client socket connects with it) then sure enough 65432 is what appeared. This is confirmed in netstat, lsof and also nmap. A simple print statement after the socket connection is successful will also confirmed that the server port is in fact using the specified port number, which is 65432.
Sorry for the inconvenience, and again much appreciation to Ottomeister for first pointing this out.

First computer doesn't receive UDP packet sent from Second computer

Today i was trying Python's socket module, but i failed to send/recieve from one PC to another.
At first i tried doing everything on single PC:
Receiver:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = socket.gethostbyname(socket.gethostname())
port = 5003
s.bind((ip, port))
while True:
data, addr = s.recvfrom(1024)
print(data, addr)
Sender:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = # I wrote ip manually from socket.gethostbyname(socket.gethostname())
port = 5003
s.sendto("Hello!", (ip, port))
Doing first script on first command line and other on second, on single PC, would work fine. But doing from one PC to another would not.
Whenever i executed Receiver script on first PC, and Sender script on second PC, there were no updates, First PC couldn't receive packet.
Also sending packet from PC2 to PC1 works, but vice versa doesn't.
Operating systems:
PC2 = Windows 8.1 64 bit;
PC1 = Mac OS X El Capitan 10.11.1 64 bit;
I have also tried adding outbound rule in Windows firewall, allowing all connections for specific port.
What could the problem be? Is it because of firewall? If not then am i doing this incorrectly?
Found the problem:
Short:
socket.gethostbyname(socket.gethostname()) contained IPv4 address of VirtualBox. Wireless LAN adapter IPv4 was different, and would receive UDP packet.
Long:
I was looking for Wireless Lan Adapter IPv4 address in ipconfig would be same in socket.gethostbyname(socket.gethostname()), but turns out
socket.gethostbyname(socket.gethostname()) would give the address of VirtualBox Host-Only Network.
When i pinged the VM IPv4 it would give timeout request, but after pinging real local IPv4 it did work.
Fix:
When oracle virtualbox are set, How to get local ip address in python

Not able to read UDP packets on a server using Python

I'm trying to stream a video from a webcam installed on a BeagleBoneBlack (linux device) to a server (Windows server). The BeagleBone is connected to the Internet using DHCP (dynamic IP) and basically sends UDP packet to a server. On the server side I implemented a simple python program using sockets that should easily read UDP packet coming from a specific IP or on a specific port. In wireshark I'm able to see the packets arriving on the server but the python program is not able to catch them. I tried to listen on different IP such as 'localhost' or specific IP but nothing seems to work.
Python program server side:
import socket
IP = '192.168.23.240' #IP of the BeagleBone on Wireshark
IP = '109.164.170.155' #IP of the router in which the BeagleBone is attached
IP = '0.0.0.0' #localhost
IP = '' #localhost
IP = '192.168.0.21' #IP localhost server
IP = 'localhost' #localhost
PORT = 5454
if __name__ == "__main__":
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((IP,PORT))
f = open('file.mp4','wb')
data, addr = s.recvfrom(4096)
print 'Receiving from: ' +str(addr)
for i in xrange(1000):
f.write(data)
data, addr = s.recvfrom(4096)
print 'receiving from ' + str(addr) + ' ...'
f.close()
s.close()
In wireshark server side:
How is possible that I'm able to read the packets in wireshark but not using a simple python program? Someone know what am I doing wrong here?
If you run your program verbatim as you posted, it listens on localhost only, while your Wireshark screenshot suggests you're sending packets to "real" NIC with private IP address.
Are you sure your program does not work? When I fed it with netcat command like so:
cat myfile | nc -u 127.0.0.1 5454
it worked:
receiving from ('127.0.0.1', 38182) ...
receiving from ('127.0.0.1', 38182) ...
receiving from ('127.0.0.1', 38182) ...
Note I was sending from localhost to localhost. This reinforces hypothesis you have a simple network config/port configuration problem, not the Python program not working.
Do netstat -a on Windows machine to see if your program really listens on indicated address.
If it does, maybe your local Windows firewall blocks the connection? Can you try turning it off for a moment?

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