I am trying to write a program for parallel checking the data rate for packets of various sizes. However, I noticed something strange that the packet size did not seem to affect the transfer time according to my program, while Unix binary pingcould disable some of the packet sizes that I use. I sent 4 packets containing the string testquest, and one that was only 2000 bytes equal to 0. However, when I printed the results, they all contained "testquest" (and were much shorter than 2000 bytes). The only thing I can conclude is that these sockets somehow get the same packet, which explains how they all have the same rtt.
I did this MCVE to illustrate the problem (you can ignore the "checksum" function, it is included for completeness, but I know from experience that it works):
import socket
import struct
import time
from multiprocessing.pool import ThreadPool as Pool
from sys import argv, byteorder
def calculate_checksum(pkt):
"""
Implementation of the "Internet Checksum" specified in RFC 1071 (https://tools.ieft.org/html/rfc1071)
Ideally this would act on the string as a series of 16-bit ints (host
packed), but this works.
Network data is big-endian, hosts are typically little-endian,
which makes this much more tedious than it needs to be.
"""
countTo = len(pkt) // 2 * 2
total, count = 0, 0
loByte, hiByte = 0, 0
while count < countTo:
if (byteorder == "little"):
loByte = pkt[count]
hiByte = pkt[count + 1]
else:
loByte = pkt[count + 1]
hiByte = pkt[count]
total += hiByte * 256 + loByte
count += 2
if countTo < len(pkt):
total += pkt[len(pkt) - 1]
total &= 0xffffffff
total = (total >> 16) + (total & 0xffff)
total += (total >> 16)
return socket.htons((~total) & 0xffff)
def ping(args):
sock, payload = args[0], args[1]
header = struct.pack("!BBH", 8, 0, 0)
checksum = calculate_checksum(header+payload)
header = struct.pack("!BBH", 8, 0, checksum)
timestamp = time.time()
sock.send(header+payload)
try:
response = sock.recv(20+len(payload))
except socket.timeout:
return 0
return (len(response), (time.time() - timestamp) * 1000)
host = argv[1]
sockets = [socket.socket(socket.AF_INET, socket.SOCK_RAW, proto=1) for i in range(12)]
for i, sock in enumerate(sockets):
sock.settimeout(0.1)
sock.bind(("0.0.0.0", i))
sock.connect((host, 1))
args = [(sockets[i], bytes(2**i)) for i in range(12)]
for arg in args:
print(ping(arg))
arg[0].close()
This actually shows me something more disturbing - it looks like rtt really decreases with increasing packet size! Calling this program (as root, to obtain socket permissions):
0
0
(24, 15.784025192260742)
(28, 0.04601478576660156)
(28, 0.025033950805664062)
(28, 0.033855438232421875)
(28, 0.03528594970703125)
(28, 0.04887580871582031)
(28, 0.05316734313964844)
(28, 0.03790855407714844)
(28, 0.0209808349609375)
(28, 0.024080276489257812)
but now notice what happens when I try to send a 2048 packet with ping:
user@mycomputer ~/src/connvitals $ time ping -c1 -s2048 $box
PING <hostname redacted> (<IP address redacted>): 2048 data bytes
--- <hostname redacted> ping statistics ---
1 packets transmitted, 0 packets received, 100.0% packet loss
real 0m11.018s
user 0m0.005s
sys 0m0.008s
The package fell not only, but it takes 11 seconds! So why - if my timeout is set to 100 ms - does this package receive a "successful" response from my python script in just ~ 0.04ms ??
Thanks in advance for any help you can provide.
Update:
, , , , , , . , , - .