jdk没有提供访问raw socket的类,在java中要实现ping有两种方法:
调用操作系统自带的ping程序,如下: /** * ping 的一种实现,调用操作系统的ping命令 */ public static int ping(String host) { String system = (String) (System.getProperty("os.name")).toLowerCase(); String command = ""; if (system.indexOf("win") != -1) { command += "ping -w 500 " + host;//设置500毫秒的超时 } else if (system.indexOf("linux") != -1) { command += "ping -t 4 " + host; //ping 四次 } else { command += "ping " + host; } int minTime = Integer.MAX_VALUE, curTime; try { Process process = Runtime.getRuntime().exec("ping " + host); BufferedReader in = new BufferedReader(new InputStreamReader( process.getInputStream())); String line = null; int count = 10, index; //最多只读10行 while ((line = in.readLine()) != null && count-- != 0) { line = line.toLowerCase(); if ((index = line.indexOf("time")) != -1) { byte[] buf = line.getBytes(); int start = 0, end = buf.length, i, j; for (i = index + 4; i < buf.length; i++) { if (Character.isDigit((char) buf[i])) { start = i; break; } } if (i == buf.length) continue; for (j = start; j < buf.length; j++) { if (Character.isLetter((char) buf[j])) { end = j; break; } } curTime = Integer.parseInt(new String(buf, start, end - start)); if (curTime < minTime) { minTime = curTime; } } } } catch (Exception ex) { return Integer.MAX_VALUE; } return minTime; }
- 用jni,如下:
先写一个Ping类,包含本地方法pingCore(..)
package zzzhc.net;
/** * @author <a href="mailto:[email protected]">zzzhc </a> * */ public class Ping {
private String host;
private int timeout = 1000;//mm
public Ping(String host) { this.host = host; }
public Ping(String host, int timeout) { this(host); this.timeout = timeout; }
/** * * @return ping time */ public int ping() { return pingCore(host, timeout); }
/** * * @param host * @param timeout * @return ping time */ public static int ping(String host, int timeout) { return pingCore(host, timeout); }
private static native int pingCore(String host, int timeout);
/** * @return Returns the host. */ public String getHost() { return host; }
/** * @param host * The host to set. */ public void setHost(String host) { this.host = host; }
/** * @return Returns the timeout. */ public int getTimeout() { return timeout; }
/** * @param timeout * The timeout to set. */ public void setTimeout(int timeout) { this.timeout = timeout; }
public static void main(String[] args) { final Ping ping = new Ping("192.168.1.1"); System.out.println("time=" + ping.ping()); }
static { System.loadLibrary("ping"); } }
实现本地方法 切换到classes目录下: 在console下执行javah zzzhc.net.Ping 得到zzzhc_net_Ping.h,然后再实现这个头文件,生成一个dll 在vc下新建一个空的dll项目,加入头文件zzzhc_net_Ping.h,新建一个zzzhc_net_Ping.c文件,实现ping的c源代码很容易找到,在zzzhc_net_Ping.c文件里只要简单调用一下就行了,代码: ping的c源码,忘记在哪找到的了 ,小有修改 头文件 // // Ping.h // #include <stdio.h> #include <stdlib.h> #include <winsock2.h> #include <Ws2tcpip.h> #ifdef _MSC_VER #pragma comment(lib,"ws2_32.lib") #endif #pragma pack(1)
#define ICMP_ECHOREPLY 0 #define ICMP_ECHOREQ 8
// IP Header -- RFC 791 typedef struct tagIPHDR { unsigned char VIHL; // Version and IHL unsigned char TOS; // Type Of Service short TotLen; // Total Length short ID; // Identification short FlagOff; // Flags and Fragment Offset unsigned char TTL; // Time To Live unsigned char Protocol; // Protocol unsigned short Checksum; // Checksum struct in_addr iaSrc; // Internet Address - Source struct in_addr iaDst; // Internet Address - Destination }IPHDR, *PIPHDR;
// ICMP Header - RFC 792 typedef struct tagICMPHDR { unsigned char Type; // Type unsigned char Code; // Code u_short Checksum; // Checksum u_short ID; // Identification u_short Seq; // Sequence unsigned char Data; // Data }ICMPHDR, *PICMPHDR;
#define REQ_DATASIZE 32 // Echo Request Data size
// ICMP Echo Request typedef struct tagECHOREQUEST { ICMPHDR icmpHdr; DWORD dwTime; unsigned char cData[REQ_DATASIZE]; }ECHOREQUEST, *PECHOREQUEST;
// ICMP Echo Reply typedef struct tagECHOREPLY { IPHDR ipHdr; ECHOREQUEST echoRequest; unsigned char cFiller[256]; }ECHOREPLY, *PECHOREPLY;
int Ping(LPCSTR pstrHost,int timeout); #pragma pack()
实现: // // PING.C -- Ping program using ICMP and RAW Sockets //
#include "ping.h"
// Internal Functions
void ReportError(LPCSTR pstrFrom); int WaitForEchoReply(SOCKET s,int timeout); u_short in_cksum(u_short *addr, int len);
// ICMP Echo Request/Reply functions int SendEchoRequest(SOCKET, LPSOCKADDR_IN); DWORD RecvEchoReply(SOCKET, LPSOCKADDR_IN, u_char *);
static int inited = 0;
void init() { WSADATA wsaData; WORD wVersionRequested = MAKEWORD(1,1); if (inited==0) { WSAStartup(wVersionRequested, &wsaData); inited = 1; } }
void destory() { if (inited==1) { WSACleanup(); } }
// Ping() // Calls SendEchoRequest() and // RecvEchoReply() and prints results int Ping(LPCSTR pstrHost,int timeout) { SOCKET rawSocket; LPHOSTENT lpHost; struct sockaddr_in saDest; struct sockaddr_in saSrc; DWORD dwTimeSent; DWORD dwElapsed; u_char cTTL; int nRet;
init();
// Create a Raw socket rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (rawSocket == SOCKET_ERROR) { ReportError("socket()"); return -1; } // Lookup host lpHost = gethostbyname(pstrHost); if (lpHost == NULL) { fprintf(stderr,"\nHost not found: %s\n", pstrHost); return -1; } // Setup destination socket address saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr)); saDest.sin_family = AF_INET; saDest.sin_port = 0;
// Tell the user what we're doing printf("\nPinging %s [%s] with %d bytes of data:\n", pstrHost, inet_ntoa(saDest.sin_addr), REQ_DATASIZE);
// Send ICMP echo request SendEchoRequest(rawSocket, &saDest);
// Use select() to wait for data to be received nRet = WaitForEchoReply(rawSocket,timeout); if (nRet == SOCKET_ERROR) { ReportError("select()"); } if (!nRet) { printf("\nTimeOut"); }
// Receive reply dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);
// Calculate elapsed time dwElapsed = GetTickCount() - dwTimeSent; printf("\nReply from: %s: bytes=%d time=%ldms TTL=%d", inet_ntoa(saSrc.sin_addr), REQ_DATASIZE, dwElapsed, cTTL); printf("\n"); nRet = closesocket(rawSocket); if (nRet == SOCKET_ERROR) ReportError("closesocket()"); return dwElapsed; }
// SendEchoRequest() // Fill in echo request header // and send to destination int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr) { static ECHOREQUEST echoReq; static nId = 1; static nSeq = 1; int nRet;
// Fill in echo request echoReq.icmpHdr.Type = ICMP_ECHOREQ; echoReq.icmpHdr.Code = 0; echoReq.icmpHdr.Checksum = 0; echoReq.icmpHdr.ID = nId++; echoReq.icmpHdr.Seq = nSeq++;
// Fill in some data to send for (nRet = 0; nRet < REQ_DATASIZE; nRet++) echoReq.cData[nRet] = ' '+nRet;
// Save tick count when sent echoReq.dwTime = GetTickCount();
// Put data in packet and compute checksum echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));
// Send the echo request nRet = sendto(s, /* socket */ (LPSTR)&echoReq, /* buffer */ sizeof(ECHOREQUEST), 0, /* flags */ (LPSOCKADDR)lpstToAddr, /* destination */ sizeof(SOCKADDR_IN)); /* address length */
if (nRet == SOCKET_ERROR) ReportError("sendto()"); return (nRet); }
// RecvEchoReply() // Receive incoming data // and parse out fields DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) { ECHOREPLY echoReply; int nRet; int nAddrLen = sizeof(struct sockaddr_in);
// Receive the echo reply nRet = recvfrom(s, // socket (LPSTR)&echoReply, // buffer sizeof(ECHOREPLY), // size of buffer 0, // flags (LPSOCKADDR)lpsaFrom, // From address &nAddrLen); // pointer to address len
// Check return value if (nRet == SOCKET_ERROR) ReportError("recvfrom()");
// return time sent and IP TTL *pTTL = echoReply.ipHdr.TTL; return(echoReply.echoRequest.dwTime); }
// What happened? void ReportError(LPCSTR pWhere) { fprintf(stderr,"\n%s error: %d\n", WSAGetLastError()); }
// WaitForEchoReply() // Use select() to determine when // data is waiting to be read int WaitForEchoReply(SOCKET s,int timeout) { struct timeval Timeout; fd_set readfds;
readfds.fd_count = 1; readfds.fd_array[0] = s; Timeout.tv_sec = timeout/1000; Timeout.tv_usec = timeout%1000; printf ("timeout=%d\n,sec=%d,usec=%d\n",timeout,timeout/1000,timeout%1000);
return(select(1, &readfds, NULL, NULL, &Timeout)); }
// // Mike Muuss' in_cksum() function // and his comments from the original // ping program // // * Author - // * Mike Muuss // * U. S. Army Ballistic Research Laboratory // * December, 1983
/* * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * */ u_short in_cksum(u_short *addr, int len) { register int nleft = len; register u_short *w = addr; register u_short answer; register int sum = 0;
/* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while( nleft > 1 ) { sum += *w++; nleft -= 2; }
/* mop up an odd byte, if necessary */ if( nleft == 1 ) { u_short u = 0;
*(u_char *)(&u) = *(u_char *)w ; sum += u; }
/* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); }
zzzhc_net_Ping.c代码如下: #include "zzzhc_net_Ping.h" #include "ping.h"
JNIEXPORT jint JNICALL Java_zzzhc_net_Ping_pingCore (JNIEnv *env, jclass jc, jstring host, jint timeout) { const char *str = (*env)->GetStringUTFChars(env, host, 0); int elapse = Ping(str,timeout); (*env)->ReleaseStringUTFChars(env, host, str); return elapse; }
编译生成ping.dll,将ping.dll放入classes下,切换到classes目录下,执行java zzzhc.net.Ping
这种方法还算直接,更好一点的办法应该是实现一个具有raw socket功能的类,再调用该类的方法实现ping,这样的话可以使java具有所有的网络功能. 
|