Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Udp broadcast #23

Open
Derf000 opened this issue Aug 30, 2023 · 2 comments
Open

Udp broadcast #23

Derf000 opened this issue Aug 30, 2023 · 2 comments

Comments

@Derf000
Copy link

Derf000 commented Aug 30, 2023

Thanks for this great library...

Is there a way to use UdpServer to read udp broadcast messages?

And second question: is multicast supported?

Thanks in advance for any reply/examples

F.

@rhelmot
Copy link
Owner

rhelmot commented Aug 31, 2023

Thanks for the interest! I've pushed a fix right now which makes udp broadcast recv work with UDPServer. If you install from github you should get this feature.

I'm afriaid I don't understand multicast enough in order to add a good interface for using it. If you can sketch the kind of tool you would like to be able to use or link an example I would gladly replicate it.

@Derf000
Copy link
Author

Derf000 commented Sep 1, 2023

Hi,
thanks for update !!!

Basically multicast is a kind of 'unicast' udp. Sending is like sending udp datagram, BUT for listening you have to 'register' ('says to router that you want to recieve multicast data').

There is some difference between Windows/Linux for binding the socket

From your server.py code it could be something like adding this :

class MCASTServer:
    """
    A simple Mcast server model. Iterating over it will yield of tuples of
    datagrams and peer addresses.
    To respond, use the respond method, which takes the response and the peer address.
    NOT SURE THAT RESPOND IS NEED HERE OR MAYBE ADAPTED !!

    :param bindto:      The address to bind to, a tuple (host, port)
    :param dgram_size:  The size of the datagram to receive. This is
                        important! If you send a message longer than the
                        receiver's receiving size, the rest of the message
                        will be silently lost! Default is 4096.

    Here is a simple server example:

    >>> from nclib import MCASTServer
    >>> server = MCASTServer(('229.1.1.1', 9111))
    >>> for message, peer in server:
	    print(peer,"|",message.decode().strip())

    """

#-------------------------------------------------------------------------------------------------------------
    def __init__(self, bindto, dgram_size=4096):
        import platform

        self.addr = bindto
        self.dgram_size = dgram_size
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        # register 'socket' to mcast group' : tell to router you are a listener for this multicast message destination
        # if platform.system() == "Windows" or 'Microsoft' in platform.uname().release:
        IP = self.get_my_ip()
        group = socket.inet_aton(bindto[0])
        iface = socket.inet_aton(IP) # listen for multicast packets on this interface.
        self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group+iface)
        # dealing with windows (or wsl) versus 'real' linux
        if platform.system() == "Windows" or 'Microsoft' in platform.uname().release:
            self.sock.bind((IP,bindto[1]))
        else :
            self.sock.bind((bindto))

    def __iter__(self):
        while True:
            packet, peer = self.sock.recvfrom(self.dgram_size)
            yield packet, peer


    def get_my_ip(self, dbg=False):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            # doesn't even have to be reachable
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except Exception:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP

    # NOT SURE IF respond is PERTINENT Here, Should be REALLY adapted
    def respond(self, packet, peer, flags=0):
        """
        Send a message back to a peer.

        :param packet:      The data to send
        :param peer:        The address to send to, as a tuple (host, port)
        :param flags:       Any sending flags you want to use for some reason
        """
        self.sock.sendto(packet, flags, peer)

    def close(self):
        """
        Tear down this server and release its resources
        """
        return self.sock.close()

Some basic code to send multicast data :

import socket
import time

MCAST_GRP = '229.1.1.1'
MCAST_PORT = 9111

#-------------------------------------------------------------------------------------------------------------
def get_my_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        # doesn't even have to be reachable
        s.connect(('10.255.255.255', 1))
        IP = s.getsockname()[0]
    except Exception:
        IP = '127.0.0.1'
    finally:
        s.close()
    return IP


IP  = get_my_ip()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, socket.inet_aton(IP))
# ttl is decrease by one at each router
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 5)
while True:
    msg = 'data from '+IP+' to :'+MCAST_GRP+':'+str(MCAST_PORT)
    sock.sendto(msg.encode('utf-8'), (MCAST_GRP, MCAST_PORT))
    time.sleep(2)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants