ICMP是网络协议的一部分,属于网络层协议(OSI模型中的第3层)。它的作用是在IP网络中传输控制消息,以响应网络故障或传输异常。在ICMP消息的流程中,碰巧也会涉及到端口号。在本文中,我们将从多个方面深入探讨icmp端口号是多少。

一、ICMP端口号介绍

ICMP消息是基于IP协议的,其消息格式中并没有端口号这个字段。因此,我们在传输ICMP消息时,并不需要设置端口号。然而,在收到ICMP消息时,是需要通过端口号将消息传递给相应的进程的。

ICMP消息是通过IP数据包传输的,在传输时使用数据包的类型码来确定如何处理数据包。在很多情况下,ICMP消息可以看作一个特定类型的数据包。因此,在处理ICMP消息时,使用的就是与处理对应类型的IP数据包时相同的端口号。

二、ICMP端口号范围

ICMP消息所使用的端口号分为两个范围:系统保留端口和动态私有端口。

系统保留端口由IANA(Internet Assigned Numbers Authority)分配,范围是0~1023,主要用于标准化的服务和应用程序。一般而言,这些端口必须由特权进程(超级用户或管理员)打开。

动态私有端口由客户端或服务器分配,范围是49152~65535。在传输ICMP消息时,大多数情况下会使用这个范围内的端口号。

三、ICMP端口号的使用

在处理ICMP消息时,使用的端口号并不是与ICMP消息绑定的。相反,它是与进程绑定的。这就是为什么需要将收到的ICMP消息传递到相应进程的原因。

在大多数情况下,系统会使用动态分配的端口来发送ICMP消息。这个过程通常是由内核处理的,因此并不需要我们手动设置端口号。我们可以通过捕获ICMP消息,然后查看源IP地址与端口号来确认消息来源。同时,我们也可以使用ICMP的类型码和代码来判断消息的类型,然后根据消息类型来执行相应的操作。

四、代码示例

import os
import socket
import struct
import time

# 构造ICMP消息
def icmp_echo_request():
    # 定义ICMP类型和代码
    icmp_type = 8 # ICMP Echo Request
    icmp_code = 0 # must be zero
    # 构造ICMP消息头部
    icmp_header = struct.pack('!BBHHH', icmp_type, icmp_code, 0, 0, 0)
    # 构造ICMP数据
    icmp_data = b'hello, world!'
    # 计算校验和
    checksum = icmp_checksum(icmp_header + icmp_data)
    # 重新构造ICMP头部,将计算出的校验和写入ICMP头部
    icmp_header = struct.pack('!BBHHH', icmp_type, icmp_code, checksum, 0, 0)
    # 最终构造ICMP消息
    icmp_msg = icmp_header + icmp_data
    return icmp_msg

# 计算ICMP校验和
def icmp_checksum(data):
    # data需要是16位的整数倍,所以我们需要将数据进行填充
    data_len = len(data)
    if (data_len % 2) != 0:
        data += b'\x00'
    # 计算校验和
    sum = 0
    for i in range(0, data_len, 2):
        word = (data[i]<>16) + (sum & 0xffff)
    sum += (sum>>16)
    checksum = ~sum & 0xffff
    return checksum

# 主函数
def main():
    # 构造ICMP消息
    icmp_msg = icmp_echo_request()
    
    # 构造IP数据报
    dest_addr = socket.gethostbyname('www.baidu.com')
    # 创建socket对象
    icmp_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
    # 设置超时时间
    icmp_socket.settimeout(5)
    # 发送ICMP消息
    icmp_socket.sendto(icmp_msg, (dest_addr, 0))
    
    # 接收ICMP消息
    try:
        recv_data, addr = icmp_socket.recvfrom(1024)
        print('recv from', addr)
        # 解析ICMP消息,获取信息类型码和代码
        icmp_type, icmp_code = struct.unpack('BB', recv_data[20:22])
        print('type:', icmp_type, 'code:', icmp_code)
    except socket.timeout:
        print('timeout')
    
    icmp_socket.close()

if __name__ == '__main__':
    main()