网上down的,share with youJAVA通过JNI调用本地C语言方法JAVA以其跨平台的特性深受人们喜爱,而又正由于它的跨平台的目的,使得它和本地机器的各种内部联系变得很少,约束了它的功能。解决JAVA对本地操作的一种方法就是JNI。JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。简单介绍及应用如下:一、JAVA中所需要做的工作 在JAVA程序中,首先需要在类中声明所调用的库名称,如下:static { System.loadLibrary(“goodluck”);}在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。 还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:public native static void set(int i); public native static int get();然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。例如程序testdll.java,内容为:public class testdll{ static{System.loadLibrary("goodluck");}public native static int get(); public native static void set(int i); public static void main(String[] args) { testdll test = new testdll(); test.set(10); System.out.println(test.get()); }} 用javac testdll.java编译它,会生成testdll.class。再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。二、C/C++中所需要做的工作 对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。接上例子。我们先看一下testdll.h文件的内容: /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class testdll */#ifndef _Included_testdll#define _Included_testdll#ifdef __cplusplusextern "C" { #endif /* * Class: testdll * Method: get * Signature: ()I */ JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); /* * Class: testdll * Method: set * Signature: (I)V */ JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);#ifdef __cplusplus} #endif#endif在具体实现的时候,我们只关心两个函数原型JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);和JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。 好,下面我们用testdll.cpp文件具体实现这两个函数: #include "testdll.h" int i = 0; JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass) {return i;} JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j) { i = j;} 编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
我也是在程序里用ipconfig /all获得的 觉得还算方便
import java.io.*;public class GetMac { //通过IP获取网卡地址 private String getMacAddressIP(String remotePcIP){ String str=""; String macAddress=""; try { Process pp= Runtime.getRuntime().exec ("nbtstat -A " + remotePcIP); InputStreamReader ir = new InputStreamReader(pp.getInputStream()); LineNumberReader input = new LineNumberReader (ir); for (int i = 1; i <100; i++) { str=input.readLine(); if (str!=null) { if(str.indexOf("MAC Address")>1) { macAddress=str.substring(str.indexOf("MAC Address")+14,str.length()); break; } } } } catch (IOException ex) {} return macAddress; } //通过机器名获取网卡地址 private String getMacAddressName(String remotePcIP){ String str=""; String macAddress=""; try { Process pp= Runtime.getRuntime().exec ("nbtstat -a " + remotePcIP); InputStreamReader ir = new InputStreamReader(pp.getInputStream()); LineNumberReader input = new LineNumberReader (ir); for (int i = 1; i <100; i++) { str=input.readLine(); if (str!=null) { if(str.indexOf("MAC Address")>1) { macAddress=str.substring(str.indexOf("MAC Address")+14,str.length()); break; } } } } catch (IOException ex) {} return macAddress; } public static void main(String[] args) { GetMac getmac; getmac=new GetMac(); String mac=""; mac=getmac.getMacAddressIP("10.67.0.6"); System.out.println(mac); mac=getmac.getMacAddressName("gxy "); System.out.println(mac); } }
同意楼上,java可以取得mac地址的.就是用process流.
to cgipro(迷途) : 现在已经很少有人用 JNI 了。直接用 C++ 写命令行程序(VC/CBuilder/Delphi写的Windows 下面的DOS程序也可), 从命令行参数输入,捕获命令行输出可以。 这样简单。 Runtime.getRuntime().exec("ipconfig/all") 可以参考 http://forum.java.sun.com/thread.jsp?forum=4&thread=245711当然,如果你要从 MAC 的 ROM 中拿时,写一个 DOS exe 程序,用 Runtime.getRuntime().exec("getmac.exe")
//之前在csdn找的 import java.net.InetAddress; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.text.ParseException; import java.util.StringTokenizer;public class NetworkInfo { private static String getMacAddress() throws IOException { String os = System.getProperty("os.name"); try { if (os.startsWith("Windows")) { return windowsParseMacAddress(windowsRunIpConfigCommand()); } else { throw new IOException("unknown operating system: " + os); } } catch (ParseException ex) { ex.printStackTrace(); throw new IOException(ex.getMessage()); } } public static void main(String[] args) { try { System.out.println("UUID = " + NetworkInfo.getMacAddress()); } catch( Exception e ) { } } private final static String windowsParseMacAddress(String ipConfigResponse) throws ParseException { String localHost = null; try { localHost = InetAddress.getLocalHost().getHostAddress(); } catch (java.net.UnknownHostException ex) { ex.printStackTrace(); throw new ParseException(ex.getMessage(), 0); } StringTokenizer tokenizer = new StringTokenizer(ipConfigResponse, "\n"); String lastMacAddress = null; while (tokenizer.hasMoreTokens()) { String line = tokenizer.nextToken().trim(); // see if line contains IP address if (line.endsWith(localHost) && lastMacAddress != null) { System.out.println( "macAddress = " + lastMacAddress ); return lastMacAddress; } // see if line contains MAC address int macAddressPosition = line.indexOf(":"); if (macAddressPosition <= 0) continue; String macAddressCandidate = line.substring(macAddressPosition + 1).trim(); if (windowsIsMacAddress(macAddressCandidate)) { lastMacAddress = macAddressCandidate; continue; } } ParseException ex = new ParseException("cannot read MAC address from [" + ipConfigResponse + "]", 0); ex.printStackTrace(); throw ex; } private final static boolean windowsIsMacAddress(String macAddressCandidate) { // TODO: use a smart regular expression if (macAddressCandidate.length() != 17) return false; return true; } private final static String windowsRunIpConfigCommand() throws IOException { Process p = Runtime.getRuntime().exec("ipconfig /all"); InputStream stdoutStream = new BufferedInputStream(p.getInputStream()); StringBuffer buffer= new StringBuffer(); for (;;) { int c = stdoutStream.read(); if (c == -1) break; buffer.append((char)c); } String outputText = buffer.toString(); stdoutStream.close(); System.out.println("outputText = " + outputText ); return outputText; } }
to cgipro(迷途) : 现在已经很少有人用 JNI 了。直接用 C++ 写命令行程序(VC/CBuilder/Delphi写的Windows 下面的DOS程序也可), 从命令行参数输入,捕获命令行输出可以。 这样简单。 Runtime.getRuntime().exec("ipconfig/all") 可以参考 http://forum.java.sun.com/thread.jsp?forum=4&thread=245711当然,如果你要从 MAC 的 ROM 中拿时,写一个 DOS exe 程序,用 Runtime.getRuntime().exec("getmac.exe")
你有没有从ROM取MAC的程序?
To: zealVampire(蚊子) 蚊子大哥,你好厉害哦!!!佩服ing
以下是使用JNI实现的读取MAC地址的代码,同时谢谢wangwenyou(王文友),以下的代码就是从jug中摘取的。你可以运行ethernet.Ethernet中main方法得到MAC Addresspackage ethernet;import java.util.*; import java.io.*; import java.security.*;/** * <p>Title: </p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: </p> * @author not attributable * @version 1.0 */ public final class Ethernet { private static native boolean getLocalEthernet(int i, byte[] ea); private final static String sDefaultLibSubDir="native"; private static boolean sLibIsLoaded=false; private Ethernet() { } public static EthernetAddress getPrimaryInterface() { checkLoadLibrary(); return getLocalEthernetAddress(0); } public static EthernetAddress[] getAllInterfaces() { checkLoadLibrary(); EthernetAddress ea; ArrayList al=new ArrayList(); for(int i=0;(ea=getLocalEthernetAddress(i))!=null; i++) { al.add(ea); } return (EthernetAddress[])(al.toArray()); } private static EthernetAddress getLocalEthernetAddress(int i) { byte[] ea=new byte[6]; if(!getLocalEthernet(i, ea)) { return null; } return EthernetAddress.valueOf(ea); } private synchronized static void checkLoadLibrary() { if(!sLibIsLoaded) { String os=System.getProperty("os.name").trim().toLowerCase(); String arch=System.getProperty("os.arch").trim().toLowerCase(); String realOS=null,realArch=null; /* * Try to figure canonical OS name, just in case some * JVMs use funny values (unlikely) */ if(os.indexOf("windows")>=0) { realOS="Win"; } else if(os.indexOf("linux")>=0) { realOS="Linux"; } else if(os.indexOf("solaris")>=0||os.indexOf("sunos")>=0) { realOS="Solaris"; } else if(os.indexOf("mac os x")>=0) { realOS="MacOSX"; } else { throw new Error("No native ethernet access library for OS '"+os+"'."); } /* * And ditto for arch value... here it's more likely weird * values exist? */ if(arch.indexOf("x86")>=0||arch.indexOf("sparc")>=0||arch.indexOf("ppc")>=0) { realArch=arch; // Apparently 'i386' means x86 architecture in JVM lingo? } else if(arch.indexOf("86")>=0||arch.indexOf("amd")>=0) { realArch="x86"; } else { throw new Error("No native ethernet access library for hardware platform with value '"+arch+"'."); } /* * Still not really guaranteed to work; not all combinations * of os + arch are either valid, or have matching library * (notably, linux+sparc and solaris+x86 are missing?) */ String libName=realOS+"_"+realArch+"_"+"EtherAddr"; try { System.loadLibrary(libName); } catch(SecurityException sex) { throw new Error("Trying to load library '"+libName+"': error; "+sex.toString()); } catch(UnsatisfiedLinkError uex) { throw new Error("Trying to load library '"+libName+"': error; "+uex.toString()); } sLibIsLoaded=true; } } /** * Test driver to test if native ethernet adapter/interface access * works ok. Tries to get the primary interface and output it; prints * out error message if access fails. */ public static void main(String[] args) { try { EthernetAddress ea=getPrimaryInterface(); System.out.println("Ok, the interface MAC-address is: "+ea.toString()); } catch(Throwable t) { System.out.println("Failed, error given: "+t.toString()); } }}
package ethernet;import java.io.Serializable; /** * EthernetAddress encapsulates the 6-byte Mac address defined in * IEEE 802.1 standard. */ public class EthernetAddress implements Serializable, Cloneable, Comparable { private final static String kHexChars="0123456789abcdefABCDEF"; private final byte[] mAddress=new byte[6]; /** * String constructor; given a 'standard' ethernet MAC address string * (like '00:C0:F0:3D:5B:7C'), constructs an EthernetAddress instance. * * Note that string is case-insensitive, and also that leading zeroes * may be omitted. Thus '00:C0:F0:3D:5B:7C' and '0:c0:f0:3d:5b:7c' are * equivalent, and a 'null' address could be passed as ':::::' as well * as '00:00:00:00:00:00' (or any other intermediate combination). * * @param addrStr String representation of the ethernet address */ public EthernetAddress(String addrStr) throws NumberFormatException { byte[] addr=mAddress; int len=addrStr.length(); /* Ugh. Although the most logical format would be the 17-char one * (12 hex digits separated by colons), apparently leading zeroes * can be omitted. Thus... Can't just check string length. :-/ */ for(int i=0, j=0; j<6; ++j) { if(i>=len) { // Is valid if this would have been the last byte: if(j==5) { addr[5]=(byte)0; break; } throw new NumberFormatException("Incomplete ethernet address (missing one or more digits"); } char c=addrStr.charAt(i); ++i; int value; // The whole number may be omitted (if it was zero): if(c==':') { value=0; } else { // No, got at least one digit? if(c>='0'&&c<='9') { value=(c-'0'); } else if(c>='a'&&c<='f') { value=(c-'a'+10); } else if(c>='A'&&c<='F') { value=(c-'A'+10); } else { throw new NumberFormatException("Non-hex character '"+c+"'"); } // How about another one? if(i<len) { c=addrStr.charAt(i); ++i; if(c!=':') { value=(value<<4); if(c>='0'&&c<='9') { value|=(c-'0'); } else if(c>='a'&&c<='f') { value|=(c-'a'+10); } else if(c>='A'&&c<='F') { value|=(c-'A'+10); } else { throw new NumberFormatException("Non-hex character '"+c+"'"); } } } } addr[j]=(byte)value; if(c!=':') { if(i<len) { if(addrStr.charAt(i)!=':') { throw new NumberFormatException("Expected ':', got ('" +addrStr.charAt(i) +"')"); } ++i; } else if(j<5) { throw new NumberFormatException("Incomplete ethernet address (missing one or more digits"); } } } } /** * Binary constructor that constructs an instance given the 6 byte * (48-bit) address. Useful if an address is saved in binary format * (for saving space for example). */ public EthernetAddress(byte[] addr) throws NumberFormatException { if(addr.length!=6) { throw new NumberFormatException("Ethernet address has to consist of 6 bytes"); } for(int i=0; i<6; ++i) { mAddress[i]=addr[i]; } } /** * Another binary constructor; constructs an instance from the given * long argument; the lowest 6 bytes contain the address. * * @param addr long that contains the MAC address in 6 least significant * bytes. */ public EthernetAddress(long addr) { for(int i=0; i<6; ++i) { mAddress[5-i]=(byte)addr; addr>>>=8; } } /** * Package internal constructor for creating an 'empty' ethernet address */ EthernetAddress() { byte z=(byte)0; for(int i=0; i<6; ++i) { mAddress[i]=z; } }
/** * Default cloning behaviour (bitwise copy) is just fine... */ public Object clone() { try { return super.clone(); } catch(CloneNotSupportedException e) { // shouldn't happen return null; } } public boolean equals(Object o) { if(!(o instanceof EthernetAddress)) { return false; } byte[] otherAddress=((EthernetAddress)o).mAddress; byte[] thisAddress=mAddress; for(int i=0; i<6; ++i) { if(otherAddress[i]!=thisAddress[i]) { return false; } } return true; } /** * Method that compares this EthernetAddress to one passed in as * argument. Comparison is done simply by comparing individual * address bytes in the order. * * @return -1 if this EthernetAddress should be sorted before the * one passed in, 1 if after and 0 if they are equal. */ public int compareTo(Object o) { byte[] thatA=((EthernetAddress)o).mAddress; byte[] thisA=mAddress; for(int i=0; i<6; ++i) { int cmp=(((int)thisA[i])&0xFF) -(((int)thatA[i])&0xFF); if(cmp!=0) { return cmp; } } return 0; } /** * Returns the canonical string representation of this ethernet address. * Canonical means that all characters are lower-case and string length * is always 17 characters (ie. leading zeroes are not omitted). * * @return Canonical string representation of this ethernet address. */ public String toString() { /* Let's not cache the output here (unlike with UUID), assuming * this won't be called as often: */ StringBuffer b=new StringBuffer(17); byte[] addr=mAddress; for(int i=0; i<6; ++i) { if(i>0) { b.append(":"); } int hex=addr[i]&0xFF; b.append(kHexChars.charAt(hex>>4)); b.append(kHexChars.charAt(hex&0x0f)); } return b.toString(); } /** * Returns 6 byte byte array that contains the binary representation * of this ethernet address; byte 0 is the most significant byte * (and so forth) * * @return 6 byte byte array that contains the binary representation */ public byte[] asByteArray() { byte[] result=new byte[6]; toByteArray(result); return result; } /** * Synonym to 'asByteArray()' * * @return 6 byte byte array that contains the binary representation */ public byte[] toByteArray() { return asByteArray(); } public void toByteArray(byte[] array) { toByteArray(array, 0); } public void toByteArray(byte[] array, int pos) { for(int i=0; i<6; ++i) { array[pos+i]=mAddress[i]; } } public long toLong() { /* Damn Java's having signed bytes sucks... they are NEVER what * anyone needs; and sign extension work-arounds are slow. */ byte[] addr=mAddress; int hi=(((int)addr[0])&0xFF)<<8 |(((int)addr[1])&0xFF); int lo=((int)addr[2])&0xFF; for(int i=3; i<6; ++i) { lo=(lo<<8)|(((int)addr[i])&0xFF); } return((long)hi)<<32|(((long)lo)&0xFFFFFFFFL); } /** * Constructs a new EthernetAddress given the byte array that contains * binary representation of the address. * * Note that calling this method returns the same result as would * using the matching constructor. * * @param addr Binary representation of the ethernet address * * @throws NumberFormatException if addr is invalid (less or more than * 6 bytes in array) */ public static EthernetAddress valueOf(byte[] addr) throws NumberFormatException { return new EthernetAddress(addr); } /** * Constructs a new EthernetAddress given the byte array that contains * binary representation of the address. * * Note that calling this method returns the same result as would * using the matching constructor. * * @param addr Binary representation of the ethernet address * * @throws NumberFormatException if addr is invalid (less or more than * 6 ints in array) */ public static EthernetAddress valueOf(int[] addr) throws NumberFormatException { byte[] bAddr=new byte[addr.length]; for(int i=0; i<addr.length; ++i) { bAddr[i]=(byte)addr[i]; } return new EthernetAddress(bAddr); } /** * Constructs a new EthernetAddress given a string representation of * the ethernet address. * * Note that calling this method returns the same result as would * using the matching constructor. * * @param addrStr String representation of the ethernet address * * @throws NumberFormatException if addr representation is invalid */ public static EthernetAddress valueOf(String addrStr) throws NumberFormatException { return new EthernetAddress(addrStr); } /** * Constructs a new EthernetAddress given the long int value (64-bit) * representation of the ethernet address (of which 48 LSB contain * the definition) * * Note that calling this method returns the same result as would * using the matching constructor. * * @param addr Long int representation of the ethernet address */ public static EthernetAddress valueOf(long addr) { return new EthernetAddress(addr); } }
关注 lapwing2002() 给的代码,经测试过。
使用C读取MAC地址有以下两种常用方法:1 使用Microsoft的Netbios API。 这是一套通过Winsock提供底层网络支持的命令。这种方法又快又准确,但是使用Netbios的最大缺点是您必须在系统中安装了Netbios服务(如果在windows网络中启用了文件共享的话,这就不是问题了)。2 使用Windows的SNMP(简单网络管理协议)扩展来取得MAC地址。以下的代码是使用方法1// Ethernet.cpp : Defines the initialization routines for the DLL. // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include <nb30.h> #include "Ethernet.h" #include "ethernet_Ethernet.h"#ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif#pragma comment (lib,"netapi32")///////////////////////////////////////////////////////////////////////////// // CEthernetApp ///////////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CEthernetApp, CWinApp) //{{AFX_MSG_MAP(CEthernetApp) // NOTE - the ClassWizard will add and remove mapping macros here. // DO NOT EDIT what you see in these blocks of generated code! //}}AFX_MSG_MAP END_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////// // CEthernetApp construction ///////////////////////////////////////////////////////////////////////////// CEthernetApp::CEthernetApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance }///////////////////////////////////////////////////////////////////////////// // The one and only CEthernetApp object ///////////////////////////////////////////////////////////////////////////// CEthernetApp theApp; ///////////////////////////////////////////////////////////////////////////// // ///////////////////////////////////////////////////////////////////////////// JNIEXPORT jboolean JNICALL Java_ethernet_Ethernet_getLocalEthernet(JNIEnv* env, jclass cls, jint id, jbyteArray ea) {
int lana_num = -1; // LAN adapter number struct ASTAT { ADAPTER_STATUS adapt; NAME_BUFFER NameBuff[30]; } Adapter; NCB Ncb; LANA_ENUM lenum; UCHAR uRetCode; int li = 0; int ln = 0; memset(&Ncb,0,sizeof(Ncb)); Ncb.ncb_command = NCBENUM; Ncb.ncb_buffer = (UCHAR*)&lenum; Ncb.ncb_length = sizeof(lenum); uRetCode = Netbios(&Ncb); if(uRetCode != 0) return JNI_FALSE; for(; li < lenum.length; li++) { lana_num = lenum.lana[li];
// prepare to get adapter status block memset(&Ncb, 0, sizeof(Ncb)); Ncb.ncb_command = NCBRESET; Ncb.ncb_lana_num = lana_num; if (Netbios(&Ncb) != NRC_GOODRET) return JNI_FALSE; // OK, lets go fetch ethernet address memset(&Ncb, 0, sizeof(Ncb)); Ncb.ncb_command = NCBASTAT; Ncb.ncb_lana_num = lana_num; strcpy((char *) Ncb.ncb_callname, "*"); memset(&Adapter, 0, sizeof(Adapter)); Ncb.ncb_buffer = (unsigned char *)&Adapter; Ncb.ncb_length = sizeof(Adapter); // If unable to determine, exit false if(Netbios(&Ncb) != 0) return JNI_FALSE; // If correct type, then see if its the one we want to check if((Adapter.adapt.adapter_type & 0xff) == 0xfe) { if(ln == id) break; ln++; } else { lana_num = -1; // This one wasn't it - clear OK indicator } } // Prepare the return value if (lana_num == -1) return JNI_FALSE;
jbyte* ba = env->GetByteArrayElements(ea,0); for(int i = 0; i < 6; i++) { ba[i] = Adapter.adapt.adapter_address[i]; } env->ReleaseByteArrayElements(ea,ba,0); return JNI_TRUE; }
另外,你用VC生成的dll文件要重命名为Win_x86_EtherAddr.dll
to jacklondon(jacklondon) galaxypilot(舵手) lapwing2002()谢谢各位,真是受益匪浅啊 谢谢
在JAVA程序中,首先需要在类中声明所调用的库名称,如下:static {
System.loadLibrary(“goodluck”);}在这里,库的扩展名字可以不用写出来,究竟是DLL还是SO,由系统自己判断。
还需要对将要调用的方法做本地声明,关键字为native。并且只需要声明,而不需要具体实现。如下:public native static void set(int i);
public native static int get();然后编译该JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就会生成C/C++的头文件。例如程序testdll.java,内容为:public class testdll{
static{System.loadLibrary("goodluck");}public native static int get();
public native static void set(int i);
public static void main(String[] args)
{
testdll test = new testdll();
test.set(10);
System.out.println(test.get());
}}
用javac testdll.java编译它,会生成testdll.class。再用javah testdll,则会在当前目录下生成testdll.h文件,这个文件需要被C/C++程序调用来生成所需的库文件。二、C/C++中所需要做的工作
对于已生成的.h头文件,C/C++所需要做的,就是把它的各个方法具体的实现。然后编译连接成库文件即可。再把库文件拷贝到JAVA程序的路径下面,就可以用JAVA调用C/C++所实现的功能了。接上例子。我们先看一下testdll.h文件的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class testdll */#ifndef _Included_testdll#define _Included_testdll#ifdef __cplusplusextern "C" {
#endif
/*
* Class: testdll
* Method: get
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_testdll_get
(JNIEnv *, jclass);
/*
* Class: testdll
* Method: set
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_testdll_set
(JNIEnv *, jclass, jint);#ifdef __cplusplus}
#endif#endif在具体实现的时候,我们只关心两个函数原型JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);和JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);这里JNIEXPORT和JNICALL都是JNI的关键字,表示此函数是要被JNI调用的。而jint是以JNI为中介使JAVA的int类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*和jclass我们一般没有必要去碰它。
好,下面我们用testdll.cpp文件具体实现这两个函数:
#include "testdll.h"
int i = 0;
JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)
{return i;}
JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)
{
i = j;}
编译连接成库文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名称要与JAVA中需要调用的一致,这里就是goodluck.dll把goodluck.dll拷贝到testdll.class的目录下,java testdll运行它,就可以观察到结果了。
觉得还算方便
{
//通过IP获取网卡地址
private String getMacAddressIP(String remotePcIP){
String str="";
String macAddress="";
try {
Process pp= Runtime.getRuntime().exec ("nbtstat -A " + remotePcIP);
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader (ir);
for (int i = 1; i <100; i++)
{
str=input.readLine();
if (str!=null)
{
if(str.indexOf("MAC Address")>1)
{ macAddress=str.substring(str.indexOf("MAC Address")+14,str.length());
break;
}
}
}
}
catch (IOException ex) {}
return macAddress;
}
//通过机器名获取网卡地址
private String getMacAddressName(String remotePcIP){
String str="";
String macAddress="";
try {
Process pp= Runtime.getRuntime().exec ("nbtstat -a " + remotePcIP);
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader (ir);
for (int i = 1; i <100; i++)
{
str=input.readLine();
if (str!=null)
{
if(str.indexOf("MAC Address")>1)
{ macAddress=str.substring(str.indexOf("MAC Address")+14,str.length());
break;
}
}
}
}
catch (IOException ex) {}
return macAddress;
}
public static void main(String[] args)
{
GetMac getmac;
getmac=new GetMac();
String mac="";
mac=getmac.getMacAddressIP("10.67.0.6");
System.out.println(mac);
mac=getmac.getMacAddressName("gxy ");
System.out.println(mac);
}
}
现在已经很少有人用 JNI 了。直接用 C++ 写命令行程序(VC/CBuilder/Delphi写的Windows 下面的DOS程序也可), 从命令行参数输入,捕获命令行输出可以。
这样简单。
Runtime.getRuntime().exec("ipconfig/all")
可以参考
http://forum.java.sun.com/thread.jsp?forum=4&thread=245711当然,如果你要从 MAC 的 ROM 中拿时,写一个 DOS exe 程序,用
Runtime.getRuntime().exec("getmac.exe")
import java.net.InetAddress;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.StringTokenizer;public class NetworkInfo {
private static String getMacAddress() throws IOException {
String os = System.getProperty("os.name");
try {
if (os.startsWith("Windows")) {
return windowsParseMacAddress(windowsRunIpConfigCommand());
} else {
throw new IOException("unknown operating system: " + os);
}
} catch (ParseException ex) {
ex.printStackTrace();
throw new IOException(ex.getMessage());
}
}
public static void main(String[] args)
{
try
{ System.out.println("UUID = " + NetworkInfo.getMacAddress());
}
catch( Exception e )
{
}
}
private final static String windowsParseMacAddress(String ipConfigResponse) throws ParseException {
String localHost = null;
try {
localHost = InetAddress.getLocalHost().getHostAddress();
} catch (java.net.UnknownHostException ex) {
ex.printStackTrace();
throw new ParseException(ex.getMessage(), 0);
}
StringTokenizer tokenizer = new StringTokenizer(ipConfigResponse, "\n");
String lastMacAddress = null;
while (tokenizer.hasMoreTokens()) {
String line = tokenizer.nextToken().trim();
// see if line contains IP address
if (line.endsWith(localHost) && lastMacAddress != null) {
System.out.println( "macAddress = " + lastMacAddress );
return lastMacAddress;
}
// see if line contains MAC address
int macAddressPosition = line.indexOf(":");
if (macAddressPosition <= 0)
continue;
String macAddressCandidate = line.substring(macAddressPosition + 1).trim();
if (windowsIsMacAddress(macAddressCandidate)) {
lastMacAddress = macAddressCandidate;
continue;
}
}
ParseException ex = new ParseException("cannot read MAC address from [" + ipConfigResponse + "]", 0);
ex.printStackTrace();
throw ex;
}
private final static boolean windowsIsMacAddress(String macAddressCandidate) {
// TODO: use a smart regular expression
if (macAddressCandidate.length() != 17)
return false;
return true;
}
private final static String windowsRunIpConfigCommand() throws IOException {
Process p = Runtime.getRuntime().exec("ipconfig /all");
InputStream stdoutStream = new BufferedInputStream(p.getInputStream());
StringBuffer buffer= new StringBuffer();
for (;;) {
int c = stdoutStream.read();
if (c == -1)
break;
buffer.append((char)c);
}
String outputText = buffer.toString();
stdoutStream.close();
System.out.println("outputText = " + outputText );
return outputText;
}
}
http://www.doomdark.org/doomdark/proj/jug/
to cgipro(迷途) :
现在已经很少有人用 JNI 了。直接用 C++ 写命令行程序(VC/CBuilder/Delphi写的Windows 下面的DOS程序也可), 从命令行参数输入,捕获命令行输出可以。
这样简单。
Runtime.getRuntime().exec("ipconfig/all")
可以参考
http://forum.java.sun.com/thread.jsp?forum=4&thread=245711当然,如果你要从 MAC 的 ROM 中拿时,写一个 DOS exe 程序,用
Runtime.getRuntime().exec("getmac.exe")
你有没有从ROM取MAC的程序?
import java.io.*;
import java.security.*;/**
* <p>Title: </p>
* <p>Description: </p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: </p>
* @author not attributable
* @version 1.0
*/
public final class Ethernet
{
private static native boolean getLocalEthernet(int i, byte[] ea); private final static String sDefaultLibSubDir="native"; private static boolean sLibIsLoaded=false; private Ethernet()
{
} public static EthernetAddress getPrimaryInterface()
{
checkLoadLibrary(); return getLocalEthernetAddress(0);
} public static EthernetAddress[] getAllInterfaces()
{
checkLoadLibrary(); EthernetAddress ea;
ArrayList al=new ArrayList(); for(int i=0;(ea=getLocalEthernetAddress(i))!=null; i++)
{
al.add(ea);
} return (EthernetAddress[])(al.toArray());
} private static EthernetAddress getLocalEthernetAddress(int i)
{
byte[] ea=new byte[6]; if(!getLocalEthernet(i, ea))
{
return null;
} return EthernetAddress.valueOf(ea);
} private synchronized static void checkLoadLibrary()
{
if(!sLibIsLoaded)
{
String os=System.getProperty("os.name").trim().toLowerCase();
String arch=System.getProperty("os.arch").trim().toLowerCase(); String realOS=null,realArch=null; /*
* Try to figure canonical OS name, just in case some
* JVMs use funny values (unlikely)
*/
if(os.indexOf("windows")>=0)
{
realOS="Win";
}
else if(os.indexOf("linux")>=0)
{
realOS="Linux";
}
else if(os.indexOf("solaris")>=0||os.indexOf("sunos")>=0)
{
realOS="Solaris";
}
else if(os.indexOf("mac os x")>=0)
{
realOS="MacOSX";
}
else
{
throw new Error("No native ethernet access library for OS '"+os+"'.");
} /*
* And ditto for arch value... here it's more likely weird
* values exist?
*/
if(arch.indexOf("x86")>=0||arch.indexOf("sparc")>=0||arch.indexOf("ppc")>=0)
{
realArch=arch; // Apparently 'i386' means x86 architecture in JVM lingo?
}
else if(arch.indexOf("86")>=0||arch.indexOf("amd")>=0)
{
realArch="x86";
}
else
{
throw new Error("No native ethernet access library for hardware platform with value '"+arch+"'.");
} /*
* Still not really guaranteed to work; not all combinations
* of os + arch are either valid, or have matching library
* (notably, linux+sparc and solaris+x86 are missing?)
*/
String libName=realOS+"_"+realArch+"_"+"EtherAddr"; try
{
System.loadLibrary(libName);
}
catch(SecurityException sex)
{
throw new Error("Trying to load library '"+libName+"': error; "+sex.toString());
}
catch(UnsatisfiedLinkError uex)
{
throw new Error("Trying to load library '"+libName+"': error; "+uex.toString());
}
sLibIsLoaded=true;
}
} /**
* Test driver to test if native ethernet adapter/interface access
* works ok. Tries to get the primary interface and output it; prints
* out error message if access fails.
*/
public static void main(String[] args)
{
try
{
EthernetAddress ea=getPrimaryInterface();
System.out.println("Ok, the interface MAC-address is: "+ea.toString());
}
catch(Throwable t)
{
System.out.println("Failed, error given: "+t.toString());
}
}}
/**
* EthernetAddress encapsulates the 6-byte Mac address defined in
* IEEE 802.1 standard.
*/
public class EthernetAddress implements Serializable, Cloneable, Comparable
{
private final static String kHexChars="0123456789abcdefABCDEF"; private final byte[] mAddress=new byte[6]; /**
* String constructor; given a 'standard' ethernet MAC address string
* (like '00:C0:F0:3D:5B:7C'), constructs an EthernetAddress instance.
*
* Note that string is case-insensitive, and also that leading zeroes
* may be omitted. Thus '00:C0:F0:3D:5B:7C' and '0:c0:f0:3d:5b:7c' are
* equivalent, and a 'null' address could be passed as ':::::' as well
* as '00:00:00:00:00:00' (or any other intermediate combination).
*
* @param addrStr String representation of the ethernet address
*/
public EthernetAddress(String addrStr) throws NumberFormatException
{
byte[] addr=mAddress;
int len=addrStr.length(); /* Ugh. Although the most logical format would be the 17-char one
* (12 hex digits separated by colons), apparently leading zeroes
* can be omitted. Thus... Can't just check string length. :-/
*/
for(int i=0, j=0; j<6; ++j)
{
if(i>=len)
{
// Is valid if this would have been the last byte:
if(j==5)
{
addr[5]=(byte)0;
break;
}
throw new NumberFormatException("Incomplete ethernet address (missing one or more digits");
} char c=addrStr.charAt(i);
++i;
int value; // The whole number may be omitted (if it was zero):
if(c==':')
{
value=0;
}
else
{
// No, got at least one digit?
if(c>='0'&&c<='9')
{
value=(c-'0');
}
else if(c>='a'&&c<='f')
{
value=(c-'a'+10);
}
else if(c>='A'&&c<='F')
{
value=(c-'A'+10);
}
else
{
throw new NumberFormatException("Non-hex character '"+c+"'");
} // How about another one?
if(i<len)
{
c=addrStr.charAt(i);
++i;
if(c!=':')
{
value=(value<<4);
if(c>='0'&&c<='9')
{
value|=(c-'0');
}
else if(c>='a'&&c<='f')
{
value|=(c-'a'+10);
}
else if(c>='A'&&c<='F')
{
value|=(c-'A'+10);
}
else
{
throw new NumberFormatException("Non-hex character '"+c+"'");
}
}
}
} addr[j]=(byte)value; if(c!=':')
{
if(i<len)
{
if(addrStr.charAt(i)!=':')
{
throw new NumberFormatException("Expected ':', got ('"
+addrStr.charAt(i)
+"')");
}
++i;
}
else if(j<5)
{
throw new NumberFormatException("Incomplete ethernet address (missing one or more digits");
}
}
}
} /**
* Binary constructor that constructs an instance given the 6 byte
* (48-bit) address. Useful if an address is saved in binary format
* (for saving space for example).
*/
public EthernetAddress(byte[] addr) throws NumberFormatException
{
if(addr.length!=6)
{
throw new NumberFormatException("Ethernet address has to consist of 6 bytes");
}
for(int i=0; i<6; ++i)
{
mAddress[i]=addr[i];
}
} /**
* Another binary constructor; constructs an instance from the given
* long argument; the lowest 6 bytes contain the address.
*
* @param addr long that contains the MAC address in 6 least significant
* bytes.
*/
public EthernetAddress(long addr)
{
for(int i=0; i<6; ++i)
{
mAddress[5-i]=(byte)addr;
addr>>>=8;
}
} /**
* Package internal constructor for creating an 'empty' ethernet address
*/
EthernetAddress()
{
byte z=(byte)0;
for(int i=0; i<6; ++i)
{
mAddress[i]=z;
}
}
* Default cloning behaviour (bitwise copy) is just fine...
*/
public Object clone()
{
try
{
return super.clone();
}
catch(CloneNotSupportedException e)
{
// shouldn't happen
return null;
}
}
public boolean equals(Object o)
{
if(!(o instanceof EthernetAddress))
{
return false;
}
byte[] otherAddress=((EthernetAddress)o).mAddress;
byte[] thisAddress=mAddress;
for(int i=0; i<6; ++i)
{
if(otherAddress[i]!=thisAddress[i])
{
return false;
}
}
return true;
} /**
* Method that compares this EthernetAddress to one passed in as
* argument. Comparison is done simply by comparing individual
* address bytes in the order.
*
* @return -1 if this EthernetAddress should be sorted before the
* one passed in, 1 if after and 0 if they are equal.
*/
public int compareTo(Object o)
{
byte[] thatA=((EthernetAddress)o).mAddress;
byte[] thisA=mAddress; for(int i=0; i<6; ++i)
{
int cmp=(((int)thisA[i])&0xFF)
-(((int)thatA[i])&0xFF);
if(cmp!=0)
{
return cmp;
}
} return 0;
}
/**
* Returns the canonical string representation of this ethernet address.
* Canonical means that all characters are lower-case and string length
* is always 17 characters (ie. leading zeroes are not omitted).
*
* @return Canonical string representation of this ethernet address.
*/
public String toString()
{
/* Let's not cache the output here (unlike with UUID), assuming
* this won't be called as often:
*/
StringBuffer b=new StringBuffer(17);
byte[] addr=mAddress; for(int i=0; i<6; ++i)
{
if(i>0)
{
b.append(":");
}
int hex=addr[i]&0xFF;
b.append(kHexChars.charAt(hex>>4));
b.append(kHexChars.charAt(hex&0x0f));
}
return b.toString();
} /**
* Returns 6 byte byte array that contains the binary representation
* of this ethernet address; byte 0 is the most significant byte
* (and so forth)
*
* @return 6 byte byte array that contains the binary representation
*/
public byte[] asByteArray()
{
byte[] result=new byte[6]; toByteArray(result); return result;
} /**
* Synonym to 'asByteArray()'
*
* @return 6 byte byte array that contains the binary representation
*/
public byte[] toByteArray()
{
return asByteArray();
} public void toByteArray(byte[] array)
{
toByteArray(array, 0);
} public void toByteArray(byte[] array, int pos)
{
for(int i=0; i<6; ++i)
{
array[pos+i]=mAddress[i];
}
} public long toLong()
{
/* Damn Java's having signed bytes sucks... they are NEVER what
* anyone needs; and sign extension work-arounds are slow.
*/
byte[] addr=mAddress;
int hi=(((int)addr[0])&0xFF)<<8
|(((int)addr[1])&0xFF);
int lo=((int)addr[2])&0xFF;
for(int i=3; i<6; ++i)
{
lo=(lo<<8)|(((int)addr[i])&0xFF);
} return((long)hi)<<32|(((long)lo)&0xFFFFFFFFL);
} /**
* Constructs a new EthernetAddress given the byte array that contains
* binary representation of the address.
*
* Note that calling this method returns the same result as would
* using the matching constructor.
*
* @param addr Binary representation of the ethernet address
*
* @throws NumberFormatException if addr is invalid (less or more than
* 6 bytes in array)
*/
public static EthernetAddress valueOf(byte[] addr) throws NumberFormatException
{
return new EthernetAddress(addr);
} /**
* Constructs a new EthernetAddress given the byte array that contains
* binary representation of the address.
*
* Note that calling this method returns the same result as would
* using the matching constructor.
*
* @param addr Binary representation of the ethernet address
*
* @throws NumberFormatException if addr is invalid (less or more than
* 6 ints in array)
*/
public static EthernetAddress valueOf(int[] addr) throws NumberFormatException
{
byte[] bAddr=new byte[addr.length]; for(int i=0; i<addr.length; ++i)
{
bAddr[i]=(byte)addr[i];
}
return new EthernetAddress(bAddr);
} /**
* Constructs a new EthernetAddress given a string representation of
* the ethernet address.
*
* Note that calling this method returns the same result as would
* using the matching constructor.
*
* @param addrStr String representation of the ethernet address
*
* @throws NumberFormatException if addr representation is invalid
*/
public static EthernetAddress valueOf(String addrStr) throws NumberFormatException
{
return new EthernetAddress(addrStr);
} /**
* Constructs a new EthernetAddress given the long int value (64-bit)
* representation of the ethernet address (of which 48 LSB contain
* the definition)
*
* Note that calling this method returns the same result as would
* using the matching constructor.
*
* @param addr Long int representation of the ethernet address
*/
public static EthernetAddress valueOf(long addr)
{
return new EthernetAddress(addr);
}
}
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <nb30.h>
#include "Ethernet.h"
#include "ethernet_Ethernet.h"#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif#pragma comment (lib,"netapi32")/////////////////////////////////////////////////////////////////////////////
// CEthernetApp
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CEthernetApp, CWinApp)
//{{AFX_MSG_MAP(CEthernetApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
// CEthernetApp construction
/////////////////////////////////////////////////////////////////////////////
CEthernetApp::CEthernetApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}/////////////////////////////////////////////////////////////////////////////
// The one and only CEthernetApp object
/////////////////////////////////////////////////////////////////////////////
CEthernetApp theApp;
/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////
JNIEXPORT jboolean JNICALL Java_ethernet_Ethernet_getLocalEthernet(JNIEnv* env, jclass cls, jint id, jbyteArray ea)
{
int lana_num = -1; // LAN adapter number struct ASTAT
{
ADAPTER_STATUS adapt;
NAME_BUFFER NameBuff[30];
} Adapter; NCB Ncb;
LANA_ENUM lenum;
UCHAR uRetCode;
int li = 0;
int ln = 0; memset(&Ncb,0,sizeof(Ncb));
Ncb.ncb_command = NCBENUM;
Ncb.ncb_buffer = (UCHAR*)&lenum;
Ncb.ncb_length = sizeof(lenum);
uRetCode = Netbios(&Ncb); if(uRetCode != 0) return JNI_FALSE; for(; li < lenum.length; li++)
{
lana_num = lenum.lana[li];
// prepare to get adapter status block
memset(&Ncb, 0, sizeof(Ncb));
Ncb.ncb_command = NCBRESET;
Ncb.ncb_lana_num = lana_num;
if (Netbios(&Ncb) != NRC_GOODRET) return JNI_FALSE; // OK, lets go fetch ethernet address
memset(&Ncb, 0, sizeof(Ncb));
Ncb.ncb_command = NCBASTAT;
Ncb.ncb_lana_num = lana_num;
strcpy((char *) Ncb.ncb_callname, "*");
memset(&Adapter, 0, sizeof(Adapter));
Ncb.ncb_buffer = (unsigned char *)&Adapter;
Ncb.ncb_length = sizeof(Adapter); // If unable to determine, exit false
if(Netbios(&Ncb) != 0) return JNI_FALSE; // If correct type, then see if its the one we want to check
if((Adapter.adapt.adapter_type & 0xff) == 0xfe)
{
if(ln == id) break;
ln++;
}
else
{
lana_num = -1; // This one wasn't it - clear OK indicator
}
} // Prepare the return value
if (lana_num == -1) return JNI_FALSE;
jbyte* ba = env->GetByteArrayElements(ea,0); for(int i = 0; i < 6; i++)
{
ba[i] = Adapter.adapt.adapter_address[i];
} env->ReleaseByteArrayElements(ea,ba,0); return JNI_TRUE;
}
谢谢