WIN32汇编语言教程:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(5)
mov @stTimeval.tv_sec,0
mov @stTimeval.tv_usec,1000000 ;超时时间1秒
invoke select,0,addr @stFdSet,NULL,NULL,addr @stTimeval
.if eax == SOCKET_ERROR
invoke _ConsolePrint,addr szErrSocket
.continue
.endif
.if eax
;********************************************************************
; 接收返回数据包
;********************************************************************
mov @dwSize,sizeof @stFrom
invoke recvfrom,@hSocket,addr szBigBuffer,\
sizeof szBigBuffer,0,addr @stFrom,addr @dwSize
.if eax == SOCKET_ERROR
invoke _ConsolePrint,addr szErrSocket
.else
mov eax,@stFrom.sin_addr
.if eax != @stDest.sin_addr
jmp @B
.endif
mov bx,word ptr szBigBuffer+\
sizeof ip_hdr+icmp_hdr.icmp_id
mov cx,word ptr szBigBuffer+\
sizeof ip_hdr+icmp_hdr.icmp_seq
.if bx != @dwID || cx != @dwSeq
jmp @B
.endif
;********************************************************************
; 如果返回的数据包是由目标主机所发的话,则显示时间和 TTL 数据
;********************************************************************
invoke inet_ntoa,eax
.if eax != NULL
invoke lstrcpy,addr @szBuffer,eax
.endif
invoke GetTickCount
sub eax,dword ptr szBigBuffer+\
sizeof ip_hdr+icmp_hdr.icmp_data
movzx ecx,szBigBuffer + ip_hdr.ip_ttl
invoke wsprintf,addr szBuffer,addr szReply,\
addr @szBuffer,PACKET_SIZE,eax,ecx
invoke _ConsolePrint,addr szBuffer
.endif
.else
invoke _ConsolePrint,addr szErrTimeout
.endif
inc @dwID
inc @dwSeq
invoke Sleep,1000
.endw
invoke closesocket,@hSocket
_Ping_Ret:
popad
ret
_Ping endp
;####################################################################
start:
call _ConsoleInit
invoke _argc
.if eax == 2
invoke WSAStartup,101h,addr stWsa
.if ! eax
invoke _argv,1,addr szHostName,\
sizeof szHostName
invoke _HostnameToIP,addr szHostName
.if eax
invoke _Ping,eax
.endif
.endif
invoke WSACleanup
.else
invoke _ConsolePrint,addr szHelp
.endif
invoke ExitProcess,NULL
;####################################################################
end start
程序首先调用_ConsoleInit子程序来获取控制台窗口的输入输出句柄,然后通过_CmdLine.asm中的_argc函数获取参数的数量,如果参数不等于2,说明用户没有输入参数或者输入了太多的参数,那么程序在显示帮助信息后直接退出。
如果输入了合适的参数,程序使用_argv子程序将参数取出并存放到szHostName变量中,然后用_HostnameToIP子程序将输入的主机名或者字符串格式的IP地址串转换成32位的IP地址,最后调用_Ping子程序来完成ICMP数据包的收发工作。
1. 主机名到IP地址的解析
Ping程序既可以将主机名当做参数输入,也可以输入IP地址字符串,比如在命令行中输入ping www.sina.com.cn的时候,程序的运行结果是:
The host [www.sina.com.cn] has 5 IP addresses:
202.106.185.203 / 202.106.185.198 / 202.106.185.196 / 202.106.185.205 /
202.106.185.204
Ping first IP 202.106.185.203 with 32 bytes of data:
Reply from 202.106.185.203: bytes=32 time=40ms TTL=244
Reply from 202.106.185.203: bytes=32 time=30ms TTL=244
Reply from 202.106.185.203: bytes=32 time=50ms TTL=244
Reply from 202.106.185.203: bytes=32 time=40ms TTL=244
而输入ping 202.106.185.204命令的时候,运行结果是:
Ping 202.106.185.204 with 32 bytes of data:
Reply from 202.106.185.204: bytes=32 time=40ms TTL=244
Reply from 202.106.185.204: bytes=32 time=40ms TTL=244
Reply from 202.106.185.204: bytes=32 time=30ms TTL=244
Reply from 202.106.185.204: bytes=32 time=40ms TTL=244
在第一个使用示范中,_HostnameToIP子程序将www.sina.com.cn解析成了5个IP地址,那么如何对主机名进行解析呢?
在_HostnameToIP子程序的一开始,首先使用inet_addr函数尝试对输入的字符串进行转换,如果输入的是“aa.bb.cc.dd”类型的IP地址字符串,那么函数将返回正确的IP地址,如果返回值是INADDR_NONE的话,说明输入的不是合法的IP地址字符串,程序则将这个字符串当做主机名来进行解析。
将主机名解析到IP地址使用gethostbyname函数:
invoke gethostbyname,lphostname
.if eax
;处理返回的数据
.endif
函数惟一的输入参数是需要解析的主机名字符串,如果解析失败将返回0,否则函数返回一个指针,指向位于WinSock接口内部缓冲区中的一个hostent结构中,这个结构的定义是:
hostent STRUCT
h_name DWORD ? ;指针,指向和IP地址对应的主机名
h_alias DWORD ? ;指针,指向一个包含别名指针的列表
h_addr WORD ? ;返回的IP地址类型
h_len WORD ? ;每个地址的长度
h_list DWORD ? ;指向一个指针列表
hostent ENDS
上页:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(4) 下页:第16章 TCP/IP和网络通信 · 16.5 ICMP协议编程(6)