1

I created a program, that receives multicast stream and analyzes its bitrate. The problem started, when I wanted to use multithreading approach here, in order to analyze many multicasts at the same time. Every multicast has it's unique addres, however they have the same port. First stream: 239.0.1.104 has constant bitrate of 10.69 Mbps, second: 239.0.1.105 has also CBR of 6.082 Mbps. The problem is, my program sums up results, and at the end i have:

  1. 16.328928
  2. 16.328928
  3. 16.802688
  4. 16.802688
  5. 16.750048
  6. 16.750048
  7. 16.813216
  8. 16.813216
  9. 16.771104
  10. 16.771104

Whereas I expect:

  1. 10.69
  2. 6.082
  3. 10.69
  4. 6.082 etc

Important: I use socket option SO_REUSEADDR which in case of multicast is equal to using both SO_REUSEADDR and SO_REUSEPORT.(Mentioned few lines below)

I read article: https://lwn.net/Articles/542629/

And also(very compact information providing):

How do SO_REUSEADDR and SO_REUSEPORT differ?

Where i read:

The meaning of SO_REUSEADDR changes for multicast addresses as it allows multiple sockets to be bound to exactly the same combination of source multicast address and port. In other words, for multicast addresses SO_REUSEADDR behaves exactly as SO_REUSEPORT for unicast addresses. Actually, the code treats SO_REUSEADDR and SO_REUSEPORT identically for multicast addresses, that means you could say that SO_REUSEADDR implies SO_REUSEPORT for all multicast addresses and the other way round.

I tried providing socket_name as parameter in order to distinguish both sockets, I tried also to add bitrateList_name and totalSize name as parameters, but always there is the same problem.

import socket
import struct
import time
import threading
from collections import Counter

MCAST_GRP = ['239.0.1.104','239.0.1.105']
MCAST_PORT1 = 12345
MCAST_PORT2 = 12345

def mcanalysis(multicast_group, MCAST_PORT):

    IS_ALL_GROUPS = True
    #scan time in seconds
    SCAN_TIME = 5
    #sampling time in seconds
    SAMPLING_TIME = 1
    bufferUDP = 2048
    totalSize = 0
    bitrateList = []

    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((multicast_group, MCAST_PORT))

    #Creating socket that gets UDP multicast packets
    for group in MCAST_GRP:
        mreq = struct.pack("4sl", socket.inet_aton(group), socket.INADDR_ANY)
        sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

    print("_____.:|   Starting analysis of multicasts!   |:._____\n")
    print("͞◌͞◌͞◌͞◌͞.:|   IP: {}    PORT: {}  |:.͞◌͞◌͞◌͞͞◌͞◌".format(multicast_group,MCAST_PORT))

    SCAN_TIME = int(SCAN_TIME *(SAMPLING_TIME**(-1)))

    for x in range(SCAN_TIME):
        stop = time.time() + SAMPLING_TIME
        while (time.time()<stop):
            data, address = sock.recvfrom(bufferUDP)
            totalSize += len(data)
        bitrateList.append(totalSize)
        print(bitrateList[x]*8/(1000000*SAMPLING_TIME))
        totalSize = 0



    bitrateList.pop(0)
    txtfile = open("Bitrate_history_ip_{}.txt".format(multicast_group),"w+")
    for x in range(SCAN_TIME-1):
        bitrateList[x] = bitrateList[x]*8/(1000000*SAMPLING_TIME)
        txtfile.write("{}.Bitrate was equal to: {} Mbps\n".format(x+1,bitrateList[x]))

    txtfile.write("Maximum bitrate value was: {} Mbps\n".format(max(bitrateList)))
    txtfile.write("Minimum bitrate value was: {} Mbps\n".format(min(bitrateList)))


t1 = threading.Thread(target=mcanalysis, args=(MCAST_GRP[0],MCAST_PORT1))
t2 = threading.Thread(target=mcanalysis, args=(MCAST_GRP[1],MCAST_PORT2))

t1.start()
t2.start()

t1.join()
t2.join()

print('End of test')
time.sleep(5)

I would to thank in advance for any information that can bring me closer to resolving this problem

  • Have you tried to read packets off the socket in a single thread which looks at the address of each packet and then queues it for handling by one of your per-address threads? – ewindes Aug 27 '19 at 16:01
  • @ewindes So it should be done in the way, that I should create another function responsible for adding `len(datagram)` to `totalSize` depending on its address that later will be threaded? – Jędrzej Kieruj Aug 28 '19 at 06:49
  • I don't know if it would help somehow, but I believe this is quite the same problem but in different language: `https://stackoverflow.com/questions/20691573/how-to-have-two-multicast-sockets-listen-to-two-multicast-channels-with-same-por` – Jędrzej Kieruj Aug 28 '19 at 07:33

0 Answers0