0

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://i.stack.imgur.com/fSSlU.jpg

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))
Yenjay
  • 55
  • 8
  • Have you considered looking up Winsock error 10035? And why the sleep? What is the problem with blocking in `recv()` in the first place? – user207421 Jul 29 '19 at 08:22
  • Yes I looked up for this error, but setting nonblocking socket shouldn't be even necessary. I just copied script from https://stackoverflow.com/questions/603852/how-do-you-udp-multicast-in-python and I adjusted it for my multicast stream. Sleep function is just for show the result per one second, not thousands of them in terminal. That's what I am asking, what may be the plausible cause of problem with this recv or recvfrom because it looks like it asks for datagrams, it gets them, it has to bite into current that is received and show it.But it's not biting into datagram on the first place – Yenjay Jul 29 '19 at 09:21
  • So if non-blocking mode isn't necessary what's your question? And what on earth do you mean by 'bite' and 'bite into current'? Please confine yourself to well-understood technical language. – user207421 Jul 29 '19 at 09:27
  • I meant the fact, that recv or recvfrom documentation says: "When no data is available, block until at least one byte is available or until the remote end is closed". So It looks like it's in blocking state because it doesn't see any available byte despite the fact that i see on wireshark datagrams coming. By "bite into current datagram" I meant that program should get and print out the current recieved datagram. – Yenjay Jul 29 '19 at 09:45
  • I would like to distinguish two blocking modes. First is from setblocking that should block the socket, and another is "blocking state" so in other words "freeze state" that occurs when recv sees "no data available". At the beginning I thought that those two are the same that's why I wanted to use setblocking(0) because i thought this causes the problem in recv. My thoughts are that recv is going into its "freeze state" because it doesn't see any available data, which should be available because i see it on wireshark. Sorry for my confusing reasoning, I am newbie in programming – Yenjay Jul 29 '19 at 10:27

2 Answers2

0

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)
Wonka
  • 1,548
  • 1
  • 13
  • 20
  • Unfortunately, the same result. I've read about chunking packets before, but in this case I still see packets coming on wireshark, but program is hanging on sock.recv in debugger :( – Yenjay Jul 29 '19 at 07:24
  • Try to use BUFF_SIZE = 1024. If you print "chunk" or "data" after concatenation on loop it display something? – Wonka Jul 29 '19 at 07:28
  • I did it even before compiling your change for the first time, because I know that it would normally work because it would split 1358 bytes into 2 chunks. Unfortunately still the same result. I am intern in company where as you probably know there are plenty of safety rules on firewall, antivirus etc. so I got problems with even receiving datagrams at the beginning, so I contacted with security department, they made changes in my security policy so now I'am receiving them, but i cannot print them and I don't know what may be the plausible cause. – Yenjay Jul 29 '19 at 07:33
  • Ok, maybe you have to check you "mreq", i never seen it. Probably it block you something too, try to dont set sock.setsockopt(.., mreq) – Wonka Jul 29 '19 at 07:38
  • Instead of `sock.recv(4096)` use `sock.recvfrom(4096)`. Read this https://stackoverflow.com/a/36116201/9342222 – Saeed Jul 29 '19 at 07:41
  • Thats a good answer @Saeed. Didnt see he declare UPD connection, if this solve his problem will edit my answer with your credits. – Wonka Jul 29 '19 at 08:08
  • It doesn't change anything. Program still looks that it's freezing on sock.recvfrom point. @Wonka But without mreq it doesn't even make datagrams arrive – Yenjay Jul 29 '19 at 08:16
  • I changed it to sock.recvfrom but it also hangs on in this moment. I have completely no idea what to do – Yenjay Jul 29 '19 at 08:23
0

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,

enter image description here

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.

Saeed
  • 142
  • 9
  • Okay I tested codes and It's actually working if i set up my own test sender and test receiver. So I believe the expected receiver(that one i want to use to MPEG-TS) has to be corrected accordingly to MPEG-TS sender. I wonder if `mreq` is problem here. I don't understand this '4s1' thing, maybe `recvfrom` is expecting other type of data than MPEG-TS provides. Do you know how can i modify `mreq` parameter in order to send bytes instead of strings? – Yenjay Jul 29 '19 at 11:56
  • I believe that port number is or may be problem. I am not sure if `setsockopt` is reffering to correct port that multicast server is sending to. As I am understanding it now: I'm trying to refer to sender by providing `MCAST_GRP` and `MCAST_PORT` which I suppose is done succesfully, because i see traffic on wireshark. The problem is that i don't know if `sock.recvfrom` is reffering to correct port that multicast is sending to. Are you able to explain how to check if it's actually like I am saying? – Yenjay Jul 29 '19 at 13:45
  • Okay, it is not '4s1', it's actually '4sl', which is just the format specifier for the struct. This line `struct.pack("4sl", socket.inet_aton(MCAST_GRP), socket.INADDR_ANY)` essentially means that create 4 byte string i-e `4s` from MCAST_GRP number and then append `l` which is again a 4 byte long integer after it. So, created mreq will have at least these 8 bytes in it, but there can be additional zero bytes appended based on the platform. Read this https://docs.python.org/2/library/struct.html#format-characters [or simply print mreq to see value] – Saeed Jul 29 '19 at 16:26
  • I don't think you need to modify `mreq` parameter, I think it seems to be configured correctly, you can print the return value of setsockopt to see if it returns success or EINVAL. My question would be, in Wireshark, once you start receiving packets, you have shown that in the picture, but if you click on any of those packets, it should show you details of that packet at the bottom and it should show you `Dst Port` field in that packet as well. What is that number? – Saeed Jul 29 '19 at 16:31
  • Okay, so there is wireshark information as well as result of defining function foobar() that does `print(sock)` : https://imgur.com/Tn8DeFz Also there is effect of changing foobar from `print(sock)` to `return sock`. The function is defined and invoked after set.setsockopt and before while loop. https://imgur.com/hLX2TSw I would like to thank You sir for devoted time. I am stuck with this code for over week. I feel helpless and I have completely no clue what can be wrong if not this destination port. Also I've been wondering if things marked in red and blue braces tell us anythin – Yenjay Jul 30 '19 at 07:31