WIN32汇编语言教程:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(3)

从表中可以看出,用于查询的ICMP消息是一一对应的,如向其他主机发送“请求回显”消息,得到的回应会是“回显应答”消息;而发送“时间戳请求”的话,得到的回应会是“时间戳应答”消息;“地址掩码应答”消息是和“地址掩码请求”消息对应的。Ping程序正是通过向其他主机发送“请求回显”消息,然后根据能否收到“回显应答”消息来判断目标主机是否在线的。

3. 校验和的计算

在发送ICMP报文的时候,必须由程序自己计算ICMP报文的校验和并将它填入ICMP首部的对应字段中,如果校验和错误的话,这个ICMP报文到达下一个路由器的时候就会被认为是在传输中发生错误而丢弃。下面是一个计算报文校验和的子程序,输入参数_lpsz指向要计算的数据,_dwSize参数指定数据的长度,子程序将返回计算完成的校验和,这个子程序存放在_CheckSum.asm中。子程序代码如下:

;####################################################################

; 计算数据包的校验和

;####################################################################

_CalcCheckSum  proc      _lpsz,_dwSize

                 local  @dwSize

 

                pushad

                  mov    ecx,_dwSize

              shr    ecx,1

             xor    ebx,ebx

              mov    esi,_lpsz

;********************************************************************

; 数据包校验和为每 16 位累加

;********************************************************************

              cld

              @@:

              lodsw

             movzx  eax,ax

              add    ebx,eax

              loop      @B

;********************************************************************

; 最后如果有单 8 位则继续累加

;********************************************************************

              test      _dwSize,1

             jz    @F

             lodsb

             movzx  eax,al

              add    ebx,eax

              @@:

;********************************************************************

; 将高 16 位并入低 16 位后取反输出

;********************************************************************

              mov    eax,ebx

             and    eax,0ffffh

              shr    ebx,16

              add    eax,ebx

              not    ax

              mov    @dwSize,eax

              popad

             mov    eax,@dwSize

              ret

 

_CalcCheckSum  endp

正如程序中所示,校验和的计算方法是将数据以字为单位累加到一个双字中,如果数据的长度是奇数,那么最后一个字节将被扩展到字以后再进行累加。累加的结果是32位的,而ICMP首部的校验和字段是16位的,校验和最终被定义为将累加结果的高16位和低16位相加后取反。在计算校验和之前,ICMP首部中的校验和字段要被首先设置为0。

16.5.3 一个Ping程序例子

好了,有了前面这些介绍,现在终于可以转入正题了,让我们来看Ping程序的源代码,代码存放在所附光盘的Chapter15\Ping目录中,目录中存放有前面列出的_CheckSum.asm和_Console.asm文件。由于控制台程序要处理命令行参数,所以程序也使用了第13章例子代码中的_CmdLine.asm文件。主文件Ping.asm的内容如下:

             .386

              .model flat, stdcall

             option casemap :none

;####################################################################

; Include

;####################################################################

include    windows.inc

include    kernel32.inc

includelib kernel32.lib

include       user32.inc

includelib    user32.lib

include       wsock32.inc

includelib    wsock32.lib

PACKET_SIZE   equ     32                 ;包大小默认为 32 字节

;####################################################################

; 数据段

;####################################################################

              .data?

szHostName    db     100 dup (?)

szBuffer      db     1024 dup (?)

szBigBuffer   db      65536 dup (?)      ;接收 ICMP_REPLY 的大缓冲区

stWsa         WSADATA <>

;********************************************************************

; 标志及命令行参数

;********************************************************************

dwOption      dd     ?

F_ABORT       equ     0001h              ;按了 Ctrl+C 终止

 

              .data

szHelp        db     'Usage: ping hostname',0dh,0ah,0ah

              db     'example:',0dh,0ah

              db     ' ping 127.0.0.1',0dh,0ah

              db     ' ping www.desthost.com',0dh,0ah,0

szErrHost     db     'Unknown host [%s]',0dh,0ah,0

szErrSocket   db     'Socket error.',0dh,0ah,0

szErrTimeout  db     'Request timed out.',0dh,0ah,0

szErrUnreach  db     'Destination host unreachable.',0dh,0ah,0

szHostOneIP   db     'The IP address of [%s] is %s',0dh,0ah,0

szPingOneIP   db     'Ping %s with 32 bytes of data:',0dh,0ah,0ah,0

szHostMoreIP  db     'The host [%s] has %d IP addresses:',0dh,0ah,0

szPingMoreIP  db     0dh,0ah,'Ping first IP %s ',

              db      'with 32 bytes of data:',0dh,0ah,0ah,0

szSpar        db     ' / ',0

szReply       db     'Reply from %s: bytes=%d time=%dms TTL=%d',0dh,0ah,0

;####################################################################

; 代码段

;####################################################################

              .code

include       _CmdLine.asm

include       _Console.asm

include       _CheckSum.asm

;####################################################################

_HostnameToIP  proc      _lpszHostName

上页:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(2) 下页:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(4)

第16章 TCP/IP和网络通信

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号