0

I have stable stream source with constant bitrate = 10.69Mbps. I'm trying to create bitrate analyser using two approaches. First one is using scapy sniff function, another one is simple packet length counter using sock.recv().

The biggest problem is that in the first one, program is 'choking' every 3-5 seconds:(10.516,10.527,10.527,9.926,10.526[Mbps])

and in the second, results are much below true values:(10.251,10.201,10.201,10.221,10.201[Mbps])

What I concluded is that approach with scapy, has to capture about 40-50 datagrams more than another approach.

import socket
import struct
import timeit
from collections import Counter
from scapy.all import sniff
#___________________________part not affecting code_______________________
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:
    sock.bind(('', MCAST_PORT))
else:
    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)


#__________________________Actual problems___________________________
packet_counts = Counter()
capturedPacketsSize = 0

## Defining custom function that sums sizes of captured packets
def custom_action(packet):
    global capturedPacketsSize
    capturedPacketsSize += len(packet)    
    #key = tuple(sorted([packet[0][1].src, packet[0][1].dst]))
    #packet_counts.update([key])

#Scapy approach
print("_____.:|   Starting analyse of bitrate!   |:._____")
for x in range(10):
    pkt = sniff(iface="eno4", filter="ip host 239.0.1.104", prn=custom_action, timeout=1)
    MCbitrate = round((capturedPacketsSize*8)/(1024*1024),3)
    print(MCbitrate)
    capturedPacketsSize = 0

#General approach
totalSize = 0
print("_____.:|   Starting analyse of bitrate!   |:._____")
while 1:
    stop = time.time() + 1
    while (time.time()<stop):
        #datagram = sock.recv(bufferUDP)
        totalSize += len(sock.recv(bufferUDP))


    theoreticalBitrate = (8*totalSize)/(1024*1024)
    print(round(theoreticalBitrate,3))
    totalSize = 0

So as you can see, idea of both is the same. But the results aren't. Do you have any ideas how to increase accuracy without scapy approach or remove 'choking' of scapy approach?


__________________________________SOLUTION__________________________________

I believe that i concluded what may be wrong. After @Shir hint, i checked that in each solution (not considering scapy chokes) there are ~1016 +/- 2 packets per second.

The result of print(len(sock.recv())) gives 1316 which is (I assume) size of decapsulated datagram. 1016*1316*8 = 10.696.448 bits.

By this simple math, I realised, that my denominator as Mega, should be (1000*1000) for Bits, where it was (1024*1024) which is correct for Bytes.

Yenjay
  • 55
  • 8
  • 2
    Did you count the total amount of packets that were captured? Did you compare it to the real amount captured by Wireshark? Your problem might be related to delays in the network or the different phase of counting. For example if we look at a series of packets numbers captured in 1 second- `6,6,6,3,6,6` represents the same amount of packets as `5.5, 5.5, 5.5, 5.5, 5.5, 5.5`, although the numbers are different and there is a "chocking" in the first one... – Shir Aug 14 '19 at 07:10
  • 1
    This hint guided me to theory, that somehow `sock.recv()` has to perceive datagram differently than scapy and that repairing approach `without scapy` should be easier. I double checked, and both approaches receive ~1016 packets per second. When i used `print(len(sock.recv(bufferUDP)))` in approach without scapy, the result is: 1316, so I believe `sock.recv()` consider only application layer(If I'm correct). When I used scapy display, it shows: https://imgur.com/OABEj9K so UDP layer shows 1324 bytes, IP 1344, but I don't know how many bytes are in packet after ethernet encapsulation. – Yenjay Aug 14 '19 at 08:37

0 Answers0