Search code examples
pythonopencvsocketsudpbroadcast

python udp broadcast sending but not receiving


I am trying a basic script that should be customized later on, but for now i need it to send a camera feed from a network connected raspberry Pi to multiple laptops on the same network.

I used udp streaming to a single device with the specific device address with the below code as a and it worked like a charm with no problem what so ever

sender

class FrameSegment():
    """ this class inits the socket in the main file then sends the frames of a video in a loop with the udp_frame method """
    MAX_IMAGE_DGRAM = 2**16 - 64 # minus 64 bytes in case UDP frame overflown

    def __init__(self, port=5000):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # for linux use SO_REUSEPORT
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.s.settimeout(0.2)
        self.PORT = port

    def udp_frame(self, img):
        compress_img = cv2.imencode(".jpg", img)[1]
        dat = compress_img.tostring()
        size = len(dat)
        num_of_segments = math.ceil(size/(self.MAX_IMAGE_DGRAM))
        array_pos_start = 0

        while num_of_segments:
            array_pos_end = min(size, array_pos_start + self.MAX_IMAGE_DGRAM)
            msg = struct.pack("B", num_of_segments) + dat[array_pos_start:array_pos_end]
            self.s.sendto(msg, ('192.168.1.110', self.PORT))
            array_pos_start = array_pos_end
            num_of_segments -= 1

Reciever

class RovCam():
    """ inits the socket in main then reads the transmitted data from said socket in a loop to display the video """
    MAX_DGRAM = 2**16 - 16

    def __init__(self,port=5000):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # for linux use SO_REUSEPORT
        self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        self.s.bind(("", port))
        self.dat = b''
        self.dump_buffer()
        print("ROV CAM : Connected successfully")

    def dump_buffer(self):
        while True:
            seg, addr = self.s.recvfrom(self.MAX_DGRAM)
            if struct.unpack("B", seg[0:1])[0] == 1:
                break

    def read(self):
        seg, addr = self.s.recvfrom(self.MAX_DGRAM)
        while struct.unpack("B", seg[0:1])[0] > 1:
            self.dat += seg[1:]
            seg, addr = self.s.recvfrom(self.MAX_DGRAM)
            
        self.dat += seg[1:]
        img = cv2.imdecode(np.fromstring(self.dat, dtype=np.uint8), 1)
        self.dat = b''
        return img

However The Problem is that if i change the address of the receiving device to a broadcast address like so ** in the sender file**

self.s.sendto(msg, ('192.168.1.255', self.PORT))

it stops working and the receiving device cannot read anything.

I then confirmed with the tcpdump tool that the receiver device is indeed receiving the sent stream over the specified port but the script has a hard time seeing that.


Solution

  • Turns out that it's a network error and when i removed the router from the network and made a smaller network with just a switch and an on board DHCP server on one of the devices used it handled the connection successfully