Python套接字窃取对方的数据包

2024-06-02 06:56:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图写一个程序来测试不同大小的数据包的并行数据传输速度。不过,我注意到一些奇怪的情况,根据我的程序,数据包的大小似乎对传输时间没有影响,而Unix ping二进制文件在我使用的一些数据包大小上会超时。我发送了4个数据包,其中包含字符串“testquest”,还有一个设置为0的只有2000字节。然而,当我打印结果时,它们包含“testquest”(并且远小于2000字节)。我唯一能得出的结论是,这些套接字都以某种方式接收相同的数据包,这就解释了它们是如何具有相同的rtt的。你知道吗

我做这个MCVE是为了说明这个问题(你可以忽略‘checksum’函数,它是完整的,但我从经验中知道它是有效的):

#!/usr/bin/env python3
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

    # Handle bytes in pairs (decoding as short ints)
    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

    # Handle last byte if applicable (odd-number of bytes)
    # Endianness should be irrelevant in this case
    if countTo < len(pkt): # Check for odd length
        total += pkt[len(pkt) - 1]

    total &= 0xffffffff # Truncate sum to 32 bits (a variance from ping.c, which
                        # uses signed ints, but overflow is unlikely in ping)

    total = (total >> 16) + (total & 0xffff)    # Add high 16 bits to low 16 bits
    total += (total >> 16)                      # Add carry from above (if any)

    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] # A host that doesn't respond to ping packets > 1500B

# 1 is ICMP protocol number
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)) # Port number should never matter for ICMP

args = [(sockets[i], bytes(2**i)) for i in range(12)]

for arg in args:
    print(ping(arg))
    arg[0].close()

这实际上让我看到了更麻烦的事情——似乎rtt实际上是随着数据包大小的增加而减少的!要获取此程序的根套接字权限,请执行以下操作:

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)

但是现在请注意,当我尝试使用ping发送大小为2048的数据包时会发生什么:

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

数据包不仅被丢弃,而且还需要11秒钟!那么为什么-如果我的超时设置为100ms-这个数据包只在~0.04ms内从我的python脚本得到“成功”响应呢??你知道吗

提前感谢您提供的任何帮助。你知道吗

更新:

我刚刚又检查了一遍,似乎是多个套接字出了问题,线程似乎与此无关。当我按顺序ping每个套接字-然后立即关闭它时,我会遇到相同的问题。你知道吗


Tags: infromimportforlentimecountargs
1条回答
网友
1楼 · 发布于 2024-06-02 06:56:34

所有套接字都相同,并且都绑定到同一主机。包中根本没有任何信息让内核知道要转到哪个套接字,raw(7)似乎意味着所有套接字都将接收它们。你知道吗

你可能会得到所有线程中的所有响应,这意味着每个线程得到的响应是预期的12倍。你知道吗

相关问题 更多 >