分享
 
 
 

用jni实现ping

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

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="zzzhc'mailto:zzzhc0508@hotmail.com">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具有所有的网络功能.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有