"Test Failed: unsupported operand type(s) for +: 'int' and 'tuple'"

"Test Failed: unsupported operand type(s) for +: 'int' and 'tuple'"

我的代码一直有问题,因为测试失败:+ 不支持的操作数类型:'int' 和 'tuple'。

我是一个不太擅长编码的超级初学者,所以我无法弄清楚问题是什么。

这是完整的代码。

我正在制作一个简单的 icmp pinger 程序。

感谢大家的帮助!!! (这是我的第一个问题所以如果我需要编辑任何东西请告诉我)

from socket import *
import os
import sys
import struct
import time
import select
import statistics
import binascii

# Should use stdev

ICMP_ECHO_REQUEST = 8


def checksum(string):
   csum = 0
   countTo = (len(string) // 2) * 2
   count = 0

   while count < countTo:
       thisVal = (string[count + 1]) * 256 + (string[count])
       csum += thisVal
       csum &= 0xffffffff
       count += 2

   if countTo < len(string):
       csum += (string[len(string) - 1])
       csum &= 0xffffffff

   csum = (csum >> 16) + (csum & 0xffff)
   csum = csum + (csum >> 16)
   answer = ~csum
   answer = answer & 0xffff
   answer = answer >> 8 | (answer << 8 & 0xff00)
   return answer



def receiveOnePing(mySocket, ID, timeout, destAddr):
   timeLeft = timeout

   while 1:
       startedSelect = time.time()
       whatReady = select.select([mySocket], [], [], timeLeft)
       howLongInSelect = (time.time() - startedSelect)
       if whatReady[0] == []:  # Timeout
           return "Request timed out."

       timeReceived = time.time()
       recPacket, addr = mySocket.recvfrom(1024)

       # Fetch the ICMP header from the IP packet

       header = recPacket[20:28]
       type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
       if type == 0 and packID == ID:
          bytesInDouble = struct.calcsize("d")
          timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
          ttls = struct.unpack("c", recPacket[8:9])[0]  
          rtt = timeReceived - timeSent
          return (rtt, ttls)

       timeLeft = timeLeft - howLongInSelect
       if timeLeft <= 0:
           return "Request timed out."


def sendOnePing(mySocket, destAddr, ID):
   # Header is type (8), code (8), checksum (16), id (16), sequence (16)

   myChecksum = 0
   # Make a dummy header with a 0 checksum
   # struct -- Interpret strings as packed binary data
   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   data = struct.pack("d", time.time())
   # Calculate the checksum on the data and the dummy header.
   myChecksum = checksum(header + data)

   # Get the right checksum, and put in the header

   if sys.platform == 'darwin':
       # Convert 16-bit integers from host to network  byte order
       myChecksum = htons(myChecksum) & 0xffff
   else:
       myChecksum = htons(myChecksum)


   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   packet = header + data

   mySocket.sendto(packet, (destAddr, 1))  # AF_INET address must be tuple, not str


   # Both LISTS and TUPLES consist of a number of objects
   # which can be referenced by their position number within the object.

def doOnePing(destAddr, timeout):
   icmp = getprotobyname("icmp")


   # SOCK_RAW is a powerful socket type. For more details:   http://sockraw.org/papers/sock_raw
   mySocket = socket(AF_INET, SOCK_RAW, icmp)

   myID = os.getpid() & 0xFFFF  # Return the current process i
   sendOnePing(mySocket, destAddr, myID)
   delay = receiveOnePing(mySocket, myID, timeout, destAddr)
   mySocket.close()
   return delay


def ping(host, timeout=1):
  # timeout=1 means: If one second goes by without a reply from the server,      # the client assumes that either the client's ping or the server's pong is lost
   dest = gethostbyname(host)
  # print("Pinging " + dest + " using Python:")
  # print("")
  # Calculate vars values and return them
   count = 0
   val = []
  # Send ping requests to a server separated by approximately one second
   for i in range(0,4):
       delay = doOnePing(dest, timeout)
       val.append(delay)
      # print(delay)
       time.sleep(1)  # one second
         
   if len(val) > 0:      
       packet_min = min(val) * 1000
       packet_avg = sum(val) / len(val) * 1000
       packet_max = max(val) * 1000
       stdev_var =  list(val) * 1000
       vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(stdev(stdev_var), 2))]
   else:
        vars = ['0', '0.0', '0', '0.0']
   return vars

if __name__ == '__main__':
   ping("google.co.il")

错误发生在这一行:

packet_avg = sum(val) / len(val) * 1000

因此val值得怀疑。按照逻辑从 doOnePing 回溯到 receiveOnePing,你会发现函数没有 return 合适的类型。

你有一些问题。我能看到的:

您正在尝试校验和,但在 python 中,使用索引 returns 一个字符串,而不是一个字符,因此生成一个字符串,而不是一个数字:

thisVal = (string[count + 1]) * 256 + (string[count])

在这种情况下,您可能想要的是:

thisVal = ord(string[count + 1]) * 256 + ord(string[count])

还有这一行:

       csum += (string[len(string) - 1])

       csum += ord(string[len(string) - 1])

然后,您将元组和可能的字符串放入 val 数组中。 您需要决定如何处理 ping 中的 errors/time。 您现在可以忽略它们:

   for i in range(0,4):
       delay = doOnePing(dest, timeout)
       if isinstance(delay, tuple):
           val.append(delay[0])
       time.sleep(1)  # one second

如果你收到一个元组,那只会添加,并且只添加元组的第一个成员,这似乎是你想要的延迟。

您在函数 receiveOnePing 中有 return (rtt, ttls),然后您 return 来自函数 doOnePing 的相同元组。之后,您将此元组附加到列表并尝试 sum 此元组列表。这会导致您提到的错误。 ping 函数(第 122 行)中需要 val.append(delay[0])

您还使用了未定义的函数stdev。应该是 statistics.stdev.

请注意,您的脚本会在超时的情况下崩溃,因为您 return 在此输入了一个字符串。 此外,代码只能由 root 运行。

UPD 下面是固定代码。

rom socket import *
import os
import sys
import struct
import time
import select
import statistics
import binascii

# Should use stdev

ICMP_ECHO_REQUEST = 8


def checksum(string):
   csum = 0
   countTo = (len(string) // 2) * 2
   count = 0

   while count < countTo:
       thisVal = (string[count + 1]) * 256 + (string[count])
       csum += thisVal
       csum &= 0xffffffff
       count += 2

   if countTo < len(string):
       csum += (string[len(string) - 1])
       csum &= 0xffffffff

   csum = (csum >> 16) + (csum & 0xffff)
   csum = csum + (csum >> 16)
   answer = ~csum
   answer = answer & 0xffff
   answer = answer >> 8 | (answer << 8 & 0xff00)
   return answer



def receiveOnePing(mySocket, ID, timeout, destAddr):
   timeLeft = timeout

   while 1:
       startedSelect = time.time()
       whatReady = select.select([mySocket], [], [], timeLeft)
       howLongInSelect = (time.time() - startedSelect)
       if whatReady[0] == []:  # Timeout
           return "Request timed out."

       timeReceived = time.time()
       recPacket, addr = mySocket.recvfrom(1024)

       # Fetch the ICMP header from the IP packet

       header = recPacket[20:28]
       type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
       if type == 0 and packID == ID:
          bytesInDouble = struct.calcsize("d")
          timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
          ttls = struct.unpack("c", recPacket[8:9])[0]  
          rtt = timeReceived - timeSent
          return (rtt, ttls)

       timeLeft = timeLeft - howLongInSelect
       if timeLeft <= 0:
           return "Request timed out."


def sendOnePing(mySocket, destAddr, ID):
   # Header is type (8), code (8), checksum (16), id (16), sequence (16)

   myChecksum = 0
   # Make a dummy header with a 0 checksum
   # struct -- Interpret strings as packed binary data
   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   data = struct.pack("d", time.time())
   # Calculate the checksum on the data and the dummy header.
   myChecksum = checksum(header + data)

   # Get the right checksum, and put in the header

   if sys.platform == 'darwin':
       # Convert 16-bit integers from host to network  byte order
       myChecksum = htons(myChecksum) & 0xffff
   else:
       myChecksum = htons(myChecksum)


   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   packet = header + data

   mySocket.sendto(packet, (destAddr, 1))  # AF_INET address must be tuple, not str


   # Both LISTS and TUPLES consist of a number of objects
   # which can be referenced by their position number within the object.

def doOnePing(destAddr, timeout):
   icmp = getprotobyname("icmp")


   # SOCK_RAW is a powerful socket type. For more details:   http://sockraw.org/papers/sock_raw
   mySocket = socket(AF_INET, SOCK_RAW, icmp)

   myID = os.getpid() & 0xFFFF  # Return the current process i
   sendOnePing(mySocket, destAddr, myID)
   delay = receiveOnePing(mySocket, myID, timeout, destAddr)
   mySocket.close()
   return delay


def ping(host, timeout=1):
  # timeout=1 means: If one second goes by without a reply from the server,      # the client assumes that either the client's ping or the server's pong is lost
   dest = gethostbyname(host)
  # print("Pinging " + dest + " using Python:")
  # print("")
  # Calculate vars values and return them
   count = 0
   val = []
  # Send ping requests to a server separated by approximately one second
   for i in range(0,4):
       delay = doOnePing(dest, timeout)
       val.append(delay[0])
      # print(delay)
       time.sleep(1)  # one second
         
   print(val)
   if len(val) > 0:      
       packet_min = min(val) * 1000
       packet_avg = sum(val) / len(val) * 1000
       packet_max = max(val) * 1000
       stdev_var =  list(val) * 1000
       vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(statistics.stdev(stdev_var), 2))]
   else:
        vars = ['0', '0.0', '0', '0.0']
   return vars

if __name__ == '__main__':
   ping("google.co.il")

>sudo python3 ping.py
[0.0778355598449707, 0.07866811752319336, 0.07798004150390625, 0.07628297805786133]