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)