Sending broadcast in Python - python

I am trying to learn to code sockets (in Python 3), I am simply trying to send a broadcast from a server and receive it from a client.
My problem is that whenever I try to send the packets to 255.255.255.255, it seems nothing is actually sent.
I tried to find the packets with wireshark but except on the loopback interface, I can't find any.
I can successfully send a message between the two computers when manually inputting the IP, and I also see the packets in wireshark.
Here's the code for the client
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(("0.0.0.0", 5005))
while True:
# sock.sendto(bytes("hello", "utf-8"), ip_co)
data, addr = sock.recvfrom(1024)
print(data)
And here's the code for the server
import socket
from time import sleep
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# sock.settimeout(2)
while True:
sock.sendto(bytes("test", "utf-8"), ("255.255.255.255", 5005))
sleep(1)
main()
Sorry if the code is ugly, I am very new to sockets and to python.

The reason is that you are broadcasting on one interface and listening on another. See this answer UDP-Broadcast on all interfaces.
You need to broadcast on all interfaces, for example using the following (purely for demonstration) code. However, keep in mind that broadcasting over IP is a legacy feature which has been dropped from IPv6. Use multicasting instead.
import socket
from time import sleep
def main():
interfaces = socket.getaddrinfo(host=socket.gethostname(), port=None, family=socket.AF_INET)
allips = [ip[-1][0] for ip in interfaces]
msg = b'hello world'
while True:
for ip in allips:
print(f'sending on {ip}')
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind((ip,0))
sock.sendto(msg, ("255.255.255.255", 5005))
sock.close()
sleep(2)
main()

If you are here to just know how to send broadcast and the solution of Mario don't work for you, because you are getting list of ips as 127.0.1.1, so there is a simpler solution:
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) as sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.sendto(msg, ("255.255.255.255", 5005))
Notice that the disadvantage here is that it will not go throw all the network interfaces, like Mario solution, just the one per the OS IP table. So keep in mind...

Related

Multicast listing between two computer is NOT working

I am trying to write a listener , which will listen to multicast data from different systems. As per my understanding, any system which is present in the same subnet will be able to get any data that will be sent to a particular muticast_grp and multicast port. But in my case, the below code is working fine for any data which will be sent to the same PC, but is NOT able to capture the data which will be sent from another PC.
I am able to see the data in Wireshark. But not in the reciver.
I don't have control over the server(sender)
import socket
import struct
import sys
MCAST_GRP = '239.255.255.250'
MCAST_PORT = 3702
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print(sock.recv(10240))
You have to listen on host '0.0.0.0', but send to the reciver IP
example
i want to send string "hi" to computer with ip "1.1.1.1"
then for sending I use
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.sendto(bytes("hi", 'utf-8'), (1.1.1.1, 3702))
and to recive
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.bind(('0.0.0.0', 3702))
print(sock.recv(3))

One server and 3 clients with using UDP in same time using Python

Good morning. I have recently started learning network and Python programming with using Raspberry Pi (emulator program on Linux) and i have a little problem. My homework is make server and three clients where this clients should get information about temperature from raspberry through server (server sends temperature) in same time (important!) but as I can see this clients get information but it is looks like 1 client get and rest wait until he receive temperature....and I really don't know what change should I make in my code : (
serwer.py
from sense_emu import SenseHat
from time import sleep
import socket
sense = SenseHat()
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
while 1:
temp = sense.temp
tempe = str(temp)
message = tempe.encode('utf-8')
sock.sendto(message, (UDP_IP, UDP_PORT))
sleep(1)
client.py
from time import sleep
import socket
UDP_IP = "127.0.0.1"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((UDP_IP, UDP_PORT))
while 1:
message, addr = sock.recvfrom(1024)
mes = str(message)
print("received message:"+mes)
sock.close()
sleep(2)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((UDP_IP, UDP_PORT))
I really thought that it should works by bind socket on each client but unfortunately not.
you seem to be misunderstanding how sockets work, I'd suggest going doing some more reading about them
some pointers and general conventions:
normally the "server" process binds to a specific "well-known" port and clients connect to that address/port
UDP is unreliable (importantly in this case packets can get lost) hence you might need a way of retransmitting values
hosts are unreliable (e.g. they might be turned off, or change IP address), you might need some way of ensuring the server doesn't send too much data to hosts that might not exist

How to fix sock.recv() blocking state in python

I am quite newbie in networking programming in python.
I use the script I found on the internet that that connects to multicast adress and recieve MPEG-TS packets. I see on wireshark that after sock.setsockopt command, MPEG-TS packets are arriving to my computer.
Screen from wireshark
https://imgur.com/XJDwd61
But the problem occurs when I want to print the sock.recv() result. I believe it's because of blocking state if I'm understanding the documentation properly. After uncommenting setblocking(0) I got 10035 error.
Do you have any clue what I need to add in order to print recieved data in terminal?
Thank you in advance.
I tried changing the buffer_size in sock.recv() to be less, equal and just how it is right now - above 1358 bytes which is amount of single datagram bytes.
import socket
import struct
import time
MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
#sock.setblocking(0)
print(f"Entering while loop")
while True:
time.sleep(1)
print(f"I'm in while loop")
print(sock.recv(4096))
Based on the example code from How do you UDP multicast in Python? when I try to run it on my system, it works fine. So, I changed it with your changes, this is the receiver.py code,
import socket
import struct
MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
IS_ALL_GROUPS = True
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if IS_ALL_GROUPS:
# on this port, receives ALL multicast groups
sock.bind(('', MCAST_PORT))
else:
# on this port, listen ONLY to MCAST_GRP
sock.bind((MCAST_GRP, MCAST_PORT))
mreq = struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
print("Entering while loop")
while True:
print("I'm in while loop")
print(sock.recv(4096))
Notice, I slightly modified print statements and removed f as it was generating an error. And this is the sender.py code,
import socket
MCAST_GRP = '239.0.1.104'
MCAST_PORT = 12345
# regarding socket.IP_MULTICAST_TTL
# ---------------------------------
# for all packets sent, after two hops on the network the packet will not
# be re-sent/broadcast (see https://www.tldp.org/HOWTO/Multicast-HOWTO-6.html)
MULTICAST_TTL = 2
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, MULTICAST_TTL)
sock.sendto(bytes("robot", 'UTF-8'), (MCAST_GRP, MCAST_PORT))
Notice that I am converting robot string into bytes with UTF-8 encoding, as this is necessary if using python3, it is not necessary in python2. This is my execution result,
As you can see when I invoke the sender, then the receiver does display robot string and loops through the while loop. It works fine.
In the case, if you are already receiving the multicast packets which you showed on your Wireshark, you need to ensure that those packets are being sent to the same port number on which you are listening, i-e 12345 in your case. If they are being sent to different port number [which is probably the case], then please change your receiver to listen on that port number to start receiving those packets.
Try this simple code, you can set less BUFF_SIZE if you want.
#BUFF_SIZE = 4096
BUFF_SIZE = 1024
data = b''
while True:
#chunk = s.recv(BUFF_SIZE)
#FOR UDP (#Saeed credits)
chuck = sock.recvfrom(BUFF_SIZE)
data += chunk
if len(chunk) < BUFF_SIZE:
break
print(data)

Python UDP Broadcast Transport Issues

I sent a UDP broadcast using Python 3.7.3.
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.bind(('', 12345))
sock.settimeout(1)
sock.sendto('ABCD'.encode(), ('255.255.255.255', 5048))
while 1:
try:
data, addr = sock.recvfrom(1024)
except socket.timeout:
print('socket timeout')
sock.sendto('ABCD'.encode(), ('255.255.255.255', 5048))
I could not confirm the broadcast on Wire Shark.
[solved]
I changed the 'Npcap Loopback Adapter' to 'Disabled' in the Ethernet adapter option, and I was able to see the UDP packets from the wire shark.
But I do not know why this is happening.
I would like advice.

python multicast with windows 2012 server receiver fail

Python multicast receiver running on windows 2012 server is not getting udp traffic. I inspected traffic and I see the udp traffic is coming across. I have a firewall udp rule for the multicast group with edge traversal allowed. I get no firewall block events. This same code works with windows 2008 server client.
On server (linux ubuntu):
PORT = 12345
import sys, os, time, socket, struct
from socket import gethostname
mc_ttl = 1
mc_group = '224.7.7.7'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(0.2)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL,
struct.pack('b', mc_ttl))
d = "my data"
while True:
sock.sendto(d, (mc_group, PORT))
on Client (windows 2012 server):
PORT = 12345
import sys, os, time, socket, struct
from socket import gethostname
mc_group = '224.7.7.7'
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('', PORT))
mreq = struct.pack("4sl", socket.inet_aton(mc_group), socket.INADDR_ANY)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print sock.recv(10240)
Note the above code works on windows 2008 server. After doing some searching I saw that theres some issues with INADDR_ANY binding to wrong address (and the requisite advice against binding to ''). Inspecting incoming udp traffic on windows client I see the multicast traffic but reciever doesn't get it.
I tried the following after reading this post. Which also did not work.
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
grp = socket.inet_aton(mc_group)
ip = socket.gethostbyname(socket.gethostname())
iface = socket.inet_aton(ip)
mreq = grp + iface
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.bind((ip, PORT))
Anyone successfully implemented receiver on windows 2012 server?
I updated the response on the other post to be a bit more explicit. Using socket.gethostbyname() is still getting the default interface, so you'll have to use socket.gethostbyname_ex() to get the extended list then select which interface you want.
Take a look at the difference:
socket.gethostbyname(socket.gethostname())
# "169.254.80.80"
socket.gethostbyname_ex(socket.gethostname())
# ("PCName", [], ["169.254.80.80", "192.168.1.10"])
In the above example, we would want to skip over the first 169.254 link-local address and select the desired 192.168.1.10 address. If socket.gethostbyname() was used in the above example, it would have been the link-local (169.254.*) address that would have been selected and your code wouldn't be doing much.
socket.gethostbyname_ex(socket.gethostname())[2][1]
# "192.168.1.10"

Categories

Resources