咱也来个 ping 函数,使用的主要是 ICMP(Internet Control Message Protocol) 提供的函数来完成的,用到了下面几个结构:
- #define WSADESCRIPTION_LEN 256
- #define WSASYS_STATUS_LEN 128
- typedef struct WSAData {
- WORD wVersion;
- WORD wHighVersion;
- char szDescription[WSADESCRIPTION_LEN+1];
- char szSystemStatus[WSASYS_STATUS_LEN+1];
- unsigned short iMaxSockets;
- unsigned short iMaxUdpDg;
- char FAR* lpVendorInfo;
- } WSADATA;
- typedef struct icmp_echo_reply {
- IPAddr Address;
- ULONG Status;
- ULONG RoundTripTime;
- USHORT DataSize;
- USHORT Reserved;
- PVOID Data;
- struct ip_option_information Options;
- } ICMP_ECHO_REPLY;
- typedef struct ip_option_information {
- UCHAR Ttl;
- UCHAR Tos;
- UCHAR Flags;
- UCHAR OptionsSize;
- PUCHAR OptionsData;
- } IP_OPTION_INFORMATION;
- typedef struct hostent {
- char FAR* h_name;
- char FAR FAR** h_aliases;
- short h_addrtype;
- short h_length;
- char FAR FAR** h_addr_list;
- } HOSTENT;
已改为类结构来实现,提供了三个公用方法:
1. Ping( tcAddress, tiTimeout ) - 第一个参数为要 ping 测试的网址或其 IP 地址,第二个参数【可选】为等待回应的时间(ms)。返回 Ping 操作是否成功
2. GetResult - 如果 Ping 操作成功,用它来检索结果信息
3. GetErrMsg - 如果 Ping 操作失败,用它来检索出错信息
下面是示例代码:
- m.oPing = NEWOBJECT( 'ping' )
- IF m.oPing.ping( INPUTBOX( '网址或 IP 地址:', 'Ping 测试', 'www.csdn.net' ))
- MESSAGEBOX( m.oPing.GetResult(), 64, '结果' )
- ELSE
- MESSAGEBOX( m.oPing.GetErrMsg(), 16, 'Error' )
- ENDIF
- DEFINE CLASS ping AS custom
- HIDDEN errmsg
- errmsg = ''
- HIDDEN echoinfo
- echoinfo = ''
- Name = 'ping'
- PROCEDURE Ping
- LPARAMETERS tcIpAddress, tiTimeout
- IF ( PCOUNT() < 2 ) OR ( 'N' != VARTYPE( m.tiTimeout )) OR ( m.tiTimeout < 0 )
- m.tiTimeout = 500
- ENDIF
- LOCAL lSuccess
- IF This.StartWSA()
- m.lSuccess = This._ping( ALLTRIM( m.tcIpAddress ), m.tiTimeout )
- WSACleanup()
- ELSE
- m.lSuccess = .F.
- ENDIF
- RETURN m.lSuccess
- ENDPROC
- HIDDEN PROCEDURE api_decl
- DECLARE Long IcmpCreateFile IN icmp
- DECLARE Long IcmpCloseHandle IN icmp Long IcmpHandle
- DECLARE Long IcmpSendEcho IN icmp ;
- Long IcmpHandle, Long DestAddr, ;
- String RequestData, Long RequestSize, Long RequestOpts, ;
- String @ ReplyBuff, Long ReplySize, Long nTimeout
- DECLARE Long WSAGetLastError IN ws2_32
- DECLARE Long WSAStartup IN ws2_32 ;
- Long wVersionRequired, String @ lpWSADATA
- DECLARE Long WSACleanup IN ws2_32
- DECLARE Long gethostbyname IN ws2_32 String szHost
- DECLARE Long inet_addr IN ws2_32 String szIpAddr
- DECLARE Long GetLastError IN WIN32API
- DECLARE Long GetIpErrorString IN Iphlpapi ;
- Long ErrorCode, String @ Buffer, Long @ Size
- DECLARE Long FormatMessage IN WIN32API ;
- Long dwFlags, Long lpSource, Long dwMessageId, Long dwLanguageId, ;
- String @ lpBuffer, Long nSize, Long Arguments
- ENDPROC
- HIDDEN PROCEDURE _ping
- LPARAMETERS tcAddress, tiTimeout
- LOCAL cTag, iAddress, hPort, lSuccess, cEcho, iErrNo
- m.lSuccess = .F.
- m.cTag = m.tcAddress
- IF ISALPHA( m.cTag )
- m.tcAddress = This.GetIpAddress( m.cTag )
- m.cTag = m.cTag + ' [ ' + m.tcAddress + ' ] '
- ENDIF
- m.iAddress = inet_addr( m.tcAddress )
- IF INLIST( m.iAddress, 0, -1 )
- This.ErrMsg = '无效的地址。'
- ELSE
- m.hPort = IcmpCreateFile()
- IF ( 0 == m.hPort )
- This.ErrMsg = This.win32msg( GetLastError())
- ELSE
- m.cEcho = REPLICATE( CHR(0), 0x100 )
- IF ( 0 == IcmpSendEcho( m.hPort, m.iAddress, 'pingtest', 8, ;
- 0, @ m.cEcho, 0x100, m.tiTimeout ))
- m.iErrNo = GetLastError()
- This.ErrMsg = This._GetErrMsg( m.iErrNo )
- ELSE
- m.lSuccess = .T.
- TEXT TO This.EchoInfo NOSHOW TEXTMERGE
- Ping:<<CHR(9)>><<m.cTag>>
- 时间:<<CHR(9)>><<CTOBIN( SUBSTR( m.cEcho, 9, 4 ), 'rs' )>> ms
- TTL:<<CHR(9)>><<CTOBIN( SUBSTR( m.cEcho, 21, 1 )+CHR(0), '2rs' )>>
- ENDTEXT
- ENDIF
- IcmpCloseHandle( m.hPort )
- ENDIF
- ENDIF
- RETURN m.lSuccess
- ENDPROC
- HIDDEN PROCEDURE win32msg
- LPARAMETERS tiErrNo
- #define FORMAT_MESSAGE_FROM_SYSTEM 0x1000
- #define FORMAT_MESSAGE_IGNORE_INSERTS 0x0200
- #define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF
- #define LANG_USER_DEFAULT 0x0804
- LOCAL cBuffer, iLen
- m.cBuffer = REPLICATE( CHR(0), 256+1 )
- m.iLen = FormatMessage( ;
- FORMAT_MESSAGE_FROM_SYSTEM ;
- + FORMAT_MESSAGE_MAX_WIDTH_MASK ;
- + FORMAT_MESSAGE_IGNORE_INSERTS, ;
- 0, m.tiErrNo, ;
- LANG_USER_DEFAULT, ;
- @ m.cBuffer, 256, 0 )
- RETURN LEFT( m.cBuffer, m.iLen )
- ENDPROC
- PROCEDURE GetErrMsg
- RETURN This.ErrMsg
- ENDPROC
- PROCEDURE GetResult
- RETURN This.EchoInfo
- ENDPROC
- HIDDEN PROCEDURE _GetErrMsg
- LPARAMETERS tiErrNo
- LOCAL iSize, cMsg
- m.iSize = 255
- m.cMsg = REPLICATE( CHR(0), m.iSize )
- IF ( 0 == GetIpErrorString( m.tiErrNo, @ m.cMsg, @ m.iSize ))
- RETURN STRCONV( LEFT( m.cMsg, m.iSize ), 6 )
- ELSE
- RETURN This.win32msg( m.tiErrNo )
- ENDIF
- ENDPROC
- HIDDEN PROCEDURE GetIpAddress
- LPARAMETERS tcHostName
- LOCAL pHostEnt, cAddr, cRet, ii
- m.pHostEnt = gethostbyname( m.tcHostName )
- IF ( 0 == m.pHostEnt )
- This.ErrMsg = This._GetErrMsg( WSAGetLastError())
- RETURN ''
- ENDIF
- m.pHostEnt = CTOBIN( SYS( 2600, m.pHostEnt+12, 4 ), 'rs' )
- m.pHostEnt = CTOBIN( SYS( 2600, m.pHostEnt, 4 ), 'rs' )
- m.cAddr = SYS( 2600, m.pHostEnt, 4 )
- m.cRet = ''
- FOR m.ii = 1 TO 4
- m.cRet = m.cRet + '.' + TRANSFORM( ASC( SUBSTR( m.cAddr, m.ii, 1 )))
- ENDFOR
- RETURN SUBSTR( m.cRet, 2 )
- ENDPROC
- HIDDEN PROCEDURE StartWSA
- #define WS_VERSION_REQD 0x0101
- LOCAL lSuccess, cWSAD
- m.cWSAD = REPLICATE( CHR(0), 402 ) && 402 = 2+2+256+1+128+1+4*3
- m.lSuccess = .F.
- IF ( 0 == WSAStartup( WS_VERSION_REQD, @ m.cWSAD ))
- IF ( WS_VERSION_REQD == CTOBIN(SUBSTR( m.cWSAD, 1, 2 ), '2rs' ) )
- m.lSuccess = .T.
- ELSE
- WSACleanup()
- This.ErrMsg = '需要支持 1.1 版的 WinSock。'
- ENDIF
- ELSE
- This.ErrMsg = '初始化 WinSock 失败。'
- ENDIF
- RETURN ( m.lSuccess )
- ENDPROC
- PROCEDURE Init
- This.api_decl()
- ENDPROC
- ENDDEFINE
代码长了点,主要是错误处理用了不少代码