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
Related
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
I'm trying to make a console chat app in python using socket library.
Whenever I send a message to the server, the server code crashes with the following message:
OSError: [WinError 10057] A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
Server code
import socket
HOST = socket.gethostbyname(socket.gethostname()) # get the ip address of PC
PORT = 5050
ADDRESS = (HOST, PORT)
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind(ADDRESS)
while True:
socket.listen()
conn, addr = socket.accept()
print(f"Connected by {addr}")
while True:
data = conn.recv(64)
print(data.decode('utf-8'))
socket.send(data)
Client code
import socket
HOST = socket.gethostbyname(socket.gethostname()) # get the ip address of PC
PORT = 5050
ADDRESS = (HOST, PORT)
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.connect(ADDRESS)
while True:
msg = input("Enter your message")
socket.send(msg.encode('utf-8'))
data = socket.recv(64)
print(data.decode('utf-8'))
What I am trying to achieve is whenever I send a message to the server, the client script should print the sent message. How can I fix that?
You're attempting to send data to your own server socket. You instead want to send to the client that you accepted.
socket.send(data)
Should be:
conn.send(data)
If you think about it, if you had multiple clients, how would you send data to a specific client? By using the socket that accept gave you.
As a side note, you probably don't want to import the module as socket, and also call your variable socket. It's fine here, but if you were to make a more complicated project, you may accidentally refer to the object when you meant to refer to the module. I'd rename the socket object to sock or server_socket to avoid shadowing.
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 send UDP video packets using sockets in Python.
The Server IP address is :192.168.67.14
The Client IP address is 192.168.67.42
The Client and Server can ping each other. Below is the code used for establishing the socket:
Server Side:
import urllib, time, os, m3u8
from socket import *
# Socket initialization
s = socket(AF_INET, SOCK_DGRAM)
host = "192.168.67.42"
port = 5000
buf = 1024
addr = (host, port)
s.connect((host, port))
ts_filenames = []
while True:
playlist = "https://sevenwestmedia01-i.akamaihd.net/hls/live/224853/TEST1/master_lowl.m3u8"
m3u8_obj = m3u8.load(playlist)
ts_segments = m3u8_obj.__dict__.values()[6]
ts_segments_str = str(m3u8_obj.segments)
for line in ts_segments_str.splitlines():
if "https://" in line:
ts_id = line[-20:]
if ts_id not in ts_filenames:
print ts_id
ts_filenames.append(ts_id)
try:
ts_segment = urllib.URLopener()
ts_segment.retrieve(line, ts_id)
except:
pass
f = open(ts_id, "rb")
data = f.read(buf)
while (data):
if (s.sendto(data, addr)):
print "sending ..."
data = f.read(buf)
Client Side
import socket
s = socket.socket()
host = '192.168.67.14'
port = 5000
s.connect((host,port))
print s.recv(1024)
s.close
Exception I get:
Traceback (most recent call last): File "client.py", line 7, in
s.connect((host,port)) File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args) socket.error: [Errno 111] Connection refused
I spent some time looking into this discussion but I still not sure what to modify. Any suggestions please ?
You have multiple problems here. First, by using connect on the server end, you're telling the operating system that you will only be communicating with IP address "192.168.67.42" port 5000. That is probably not what you intended. (A server usually talks to whatever client wants to talk to it.)
Second, by not specifying SOCK_DGRAM in your client, you're getting the default socket type, which is SOCK_STREAM. That means your client is trying to connect to your server on TCP port 80 -- not UDP port 80 (the two namespaces are totally separate).
For a UDP "session", both sides need an IP address and a port number. If you do not bind a port specifically, the operating system will choose one for you quasi-randomly. In order to link up client and server, they must agree on at least one of those.
So a typical UDP server will bind to a well-known port (presumably you intended 5000 for that purpose). Then the client can connect to the server at that port. The code would look something like this (sans error handling):
Server side:
# Create socket
s = socket(AF_INET, SOCK_DGRAM)
# Bind to our well known port (leave address unspecified
# allowing us to receive on any local network address)
s.bind(('', 5000))
# Receive from client (so we know the client's address/port)
buffer, client_addr = s.recvfrom(1024)
# Now we can send to the client
s.sendto(some_buffer, client_addr)
The client is close to what you have, but you should send some data from the client to the server first so that the server knows your address:
s = socket(AF_INET, SOCK_DGRAM)
# Create connection to server (the OS will automatically
# bind a port for the client)
s.connect((host, port))
# Send dummy data to server so it knows our address/port
s.send(b'foo')
buffer = s.recv(1024)
Note that because you have used connect on the client side, you've permanently specified your peer's address and don't need to use recvfrom and sendto.
On the client side, this is wrong:
s = socket.socket()
for receiving UDP packets, you need to create a UDP socket, same as you did on the server side:
s = socket(AF_INET, SOCK_DGRAM)
Also, if you want your client to be able to receive UDP packets you will need to bind() it to port 5000 (connect() is neither necessary nor sufficient for that).
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))