I want ro receive some data that is sent as a UDP packet over VPN. So wrote (mostly copied) this program in python:
import socket
import sys
HOST = ???????
PORT = 80
# SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((HOST,PORT))
data,addr = sock.recv(1024)
print "Received: %s" % data
print "Addr: %s" % addr
What should I use as host? I know the IP of the sender but it seems anything thats not local gives me socket.error: [Errno 10049]. The IP that the VPN gives me (the same IP that the sender sends to, that is)? Or just localhost?
The host argument is the host IP you want to bind to. Specify the IP of one of your interfaces (Eg, your public IP, or 127.0.0.1 for localhost), or use 0.0.0.0 to bind to all interfaces. If you bind to a specific interface, your service will only be available on that interface - for example, if you want to run something that can only be accessed via localhost, or if you have multiple IPs and need to run different servers on each.
"0.0.0.0" will listen for all incoming hosts. For example,
sock.bind(("0.0.0.0", 999))
data,addr = sock.recv(1024)
Use:
sock.bind(("", 999))
Related
I tried setting up a TCP socket with Python, and it works totally fine as long as I'm in the same network. But my problem is that I can't get it to work if one of the devices isn't in the same network.
I already tried setting the bind IP to '0.0.0.0', and if I try connecting I get socket error 10060. I think the problem probably has something to do with port-forwarding, but I don't know how to do it in Python.
Here is the code I used to test it, and I don't know how I get the public IP from my device in Python (not the gethostbyname() function, that only returns the private IP).
I hope you can help me.
Server.py
HOST = '0.0.0.0'
PORT = 5000
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
while True:
text = input("Enter text: ").encode("utf-8")
send_msg(conn,text)
echo = recv_msg(conn).decode("utf-8")
print(echo)
client.py
#HOST = '192.168.0.220'
HOST = 'x.x.x.x' #ip address of server
PORT = 5000`
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
while True:
data = recv_msg(s)
send_msg(s,data)
def send_msg(sock, msg):
msg = struct.pack('>Q', len(msg)) + msg
sock.sendall(msg)
def recv_msg(sock):
raw_msglen = recvall(sock, 8)
if not raw_msglen:
return None
msglen = struct.unpack('>Q', raw_msglen)[0]
return recvall(sock, msglen)
def recvall(sock: socket.socket, n):
data = bytearray()
while len(data) < n:
packet = sock.recv(n - len(data))
if not packet:
return None
data.extend(packet)
return data
The code shown is fine. bind()'ing the server to 0.0.0.0 is typically the correct thing to do, that allows it to listen on all local IPs installed on its machine. Or, you can bind() it to the specific IP of the adapter that is connected to your network. Either way is fine.
On the client side, if the client is on the same network, it can connect() to the server's LAN IP, and all is well.
The problem comes when the client is not on the same network. That means the client simply cannot connect to your server directly. There is no physical route to facilitate that connection. So, to remedy that, you must setup a Port Forwarding rule in your LAN router. You must open a public IP/Port on the router's WAN, and map it to the server's LAN IP/Port. Then the client will be able to connect to the router's WAN IP/Port and let the router forward the packets to the server's LAN IP/Port, and vice versa.
If your router supports uPNP, your server code can setup this Port Forwarding programmably. There are uPNP libraries available, or your OS may even have APIs for that. Otherwise, your router admin must setup the Port Forwarding rule by hand.
To discover your router's WAN IP for the client to connect to, your server code can query an external site like https://whatismyip.com, or even query the router directly (if the router has an API for this purpose). Otherwise, you should subscribe to a 3rd party Dynamic DNS service that assigns you a static hostname that the client can always connect to, and then your server code, or even the router itself, can update the IP for that hostname whenever the router's WAN IP changes.
I am using the socket library for Python. I'm trying to make a local server. The server runs correctly, but the client does not. When I say that I want to connect to AF_INET it gives me a TypeError. It says that the AF_INET address must be a tuple, when it is a string.
Here is my code:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(socket.gethostname())
print("client successfully started")
msg = s.recv(1024)
print(msg.decode("utf-8"))
I am using version 3.10.0 (of python), if that helps.
From the socket documentation:
A pair (host, port) is used for the AF_INET address family, where host is a string representing either a hostname in internet
domain notation like 'daring.cwi.nl' or an IPv4 address like
'100.50.200.5', and port is an integer.
For IPv4 addresses, two special forms are accepted instead of a host address: '' represents INADDR_ANY, which is used to bind to
all interfaces, and the string '<broadcast>' represents
INADDR_BROADCAST. This behavior is not compatible with IPv6,
therefore, you may want to avoid these if you intend to support IPv6
with your Python programs.
For a local server, you can just use 'localhost' for the client.
Example:
from socket import *
PORT = 5000
# for server
s = socket() # AF_INET and SOCK_STREAM are the default
s.bind(('',PORT)) # must be a 2-tuple (note the parentheses)
s.listen()
c,a = s.accept()
# for client
s = socket()
s.connect(('localhost',PORT))
The connect function takes in a tuple, so you need an extra set of parentheses. It's not clear what you are trying to do with gethostname. Also, you need to have a port number to connect to. If you are trying to listen to localhost, the code would look like this:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Add socket.gethostbyname and add port number
s.connect((socket.gethostbyname(socket.gethostname()), 8089)) # Add another set of parentheses as you need a tuple
print("client successfully started")
msg = s.recv(1024)
print(msg.decode("utf-8"))
Even this may result in a ConnectionRefusedError: [Errno 61] Connection refused error, because you might have to to use the IP address from the server. Something like: 192.168.0.1. To get your IP address, do ipconfig in your cmd prompt (on Windows).
So the correct code would look like this:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect('192.168.0.1', 8089)) # Your IP instead of 192.168.0.1
print("client successfully started")
msg = s.recv(1024)
print(msg.decode("utf-8"))
I found the answer!
here is the code for everyone that has the same problem as me
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((socket.gethostname(),3000)) #you can use another port if you want
s.listen(5)
print("server successfully started")
while True:
clientsocket, address = s.accept()
print(f"connection has been established from {address}")
clientsocket.send(bytes("Welcome to the chatroom!", "utf-8")) #this sends message to the client in utf-8
When I try to ping a Minecraft server via LAN, the documents say the following:
In Singeplayer there is a function called "Open to LAN". Minecraft (in the serverlist) binds a UDP port and listens for connections to 224.0.2.60:4445 (Yes, that is the actual IP, no matter in what network you are or what your local IP Address is)" ....... client side, bind a UDP socket and listen for connections. You can use a MulticastSocket for that.
I tried to implement this in Python in the following way:
import socket
UDP_IP = "224.0.2.60"
UDP_PORT = 4445
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print("received message: %s" % data)
Which gave me an OSError: [WinError 10049] error.
Please help :( I have no idea what's wrong with my code.
By the way, sending packets to that port works, and the fake server shows up on the Minecraft app.
You cannot bind to a multicast address like that. It is somewhat more involved.
I recommend to read this article that explains all the details of using multicast with Python.
I am trying to set up a UDP unicast between two linux-machines on my local network, using the python sockets library. I manage to send and receive the package using the following code:
Send
import socket
HOST = '192.168.1.194' # IP of remote machine
PORT = 47808
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto('Hello UDP', (HOST, PORT))
s.close()
Receive
import socket
HOST = ''
PORT = 47808
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((HOST, PORT))
while True:
try:
data, addr = s.recvfrom(1024)
print 'Received: {0} # {1}'.format(data, addr)
except KeyboardInterrupt:
break
s.close()
However, binding to '' makes the receiving code accept packets from any local interface. If I try to bind to the IP address of the sending machine specifically (changing HOST = ''to HOST = '192.168.1.130' in the receiving code), I get a socket.error: [Errno 99] Cannot assign requested address. No other services are using the port, and I have tried different ports with no change in behaviour. How can I configure my socket to only receive packets from a specific address?
First, let's deal with the error you are seeing. .bind() names the local end of the socket, not the remote. So the host part must refer to the local machine (e.g., 'localhost', '127.0.0.1, '192.168.1.194', or '' (wildcard for all local interfaces).) So, when you specify an address that isn't local to the machine running .bind(), you get an error.
Second, there is no way to "configure my socket to only receive packets from a specific address." As an alternative, you can use the returned address from .recvfrom() to ignore data you don't care about.
data, addr = s.recvfrom(1024)
if addr != '192.168.1.130':
continue
socket.error: [Errno 49] Can't assign requested address
I'm trying to construct a dns message using udp. However, my socket connection doesn't seem to be working for UDP. I am unable to bind and send using the same socket. Is this expected behavior?
I thought this would work since I saw it here:
https://github.com/rthalley/dnspython/blob/master/dns/query.py#L213-L215
UDP.py
import socket
source_address = ('127.0.0.1', 20202)
destination_address = ('8.8.8.8', 53)
data = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(source_address)
print 'Sending UDP to {}'.format(destination_address)
s.sendto(data, destination_address)
# listen for response with s.recvfrom(16384)
source_address = ('127.0.0.1', 20202)
You're trying to send from your loopback device. You can't do that, it's local to your machine only. Use one of your external IP addresses, or bind your socket to the wildcard address 0.0.0.0 .