(也许我用烦人的细节级别解释了这个问题,tl; dr版本在底部)
我一直在尝试使用JNA在Java中创建一个简单的Winsock测试应用程序。我调用的第一个函数是WSAStartup(),使用以下代码:
public interface Ws2_32 extends Library {
Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);
int WSAStartup(short version, LPWSADATA lpwsaData);
}
public static void main(String[] args){
LPWSADATA lpwsaData = new LPWSADATA();
short version = 2;
int result = Ws2_32.INSTANCE.WSAStartup(version,lpwsaData);
System.out.println("WSAStartup() returned: " + result);
if((resultado = Ws2_32.INSTANCE.WSAStartup(version,lpwsaData)) == 0){
System.out.println("LPWSADATA struct:");
System.out.println("wVersion: " + lpwsaData.wVersion);
System.out.println("wHighVersion: " + lpwsaData.wHighVersion);
System.out.print("szDescription: ");
for(byte b : lpwsaData.szDescription){
System.out.print((char) b);
}
System.out.print("\n");
System.out.print("szSystemStatus: ");
for(byte b : lpwsaData.szSystemStatus){
System.out.print((char) b);
}
System.out.print("\n");
System.out.println("iMaxSockets: " + lpwsaData.iMaxSockets);
System.out.println("iMaxUdpDg: " + lpwsaData.iMaxUdpDg");
}
}
这有效,并且我得到以下值:
wVersion:2
wHighVersion:514
sz说明:WinSock 2.0
szSystemStatus:正在运行
iMaxSockets:0
iMaxUdpDg:0
成功返回WSAStartup()之后,我尝试调用WSAEnumProtocols(),但出现以下错误:
线程“主”中的异常java.lang.UnsatisfiedLinkError:查找函数'WSAEnumProtocols'时出错:找不到指定的过程。
然后,我使用Dependency Walker打开了ws2_32.dll,发现没有使用该名称的函数。我只发现了3个具有类似名称的名称:WSAEnumProtocolsA(),WSAEnumProtocolsW()和WSCEnumProtocols()。
我将使用WSAEnumProtocolsA()作为示例,但是我对所有3个对象都使用了下一个过程,并得到了相同的结果:
首先,我调用了WSAStartup(),没有错误返回。
根据WSAEnumProtocols的MSDN定义,对该函数的首次调用应如下所示:
WSAEnumProtocols(null,wsaprotocol_info,lpdwBufferLength)
第一个参数为null,第二个参数为指向WSAPROTOCOL_INFO结构的指针,第三个为缓冲区的长度。如果该长度为零,则该函数应返回-1(SOCKET_ERROR),并且对WSAGetLastError()的调用应返回WSAENOBUFS,这意味着缓冲区不够大,无法包含WSAEnumProtocols()返回的信息,并且应设置变量lpdwBufferLength具有可以传递给WSAEnumProtocols的最小缓冲区大小,以检索所有请求的信息。
我无法使它正常工作。 WSAEnumProtocols()返回-1,但lpdwBufferLength的值未更改,WSAGetLastError()返回0而不是10055(WSAENOBUFS)
我还尝试使用WSASetLastError()并将其设置为其他错误代码,然后调用WSAGetLastError(),但它始终返回0。
tl; dr
我无法使WSAEnumProtocols(null,wsaprotocol_info,lpdwBufferLength)工作。 WSAEnumProtocols()返回-1,但lpdwBufferLength的值未更改,WSAGetLastError()返回0而不是10055(WSAENOBUFS)
更新:
这是我用来声明Winsock函数的接口
public interface Ws2_32 extends Library {
Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);
int WSAStartup(short version, LPWSADATA lpwsaData);
int WSAEnumProtocolsW(int[] lpiProtocols, WSAPROTOCOL_INFO lpProtocolBuffer, int lpdwBufferLength);
int WSACleanup();
int WSAGetLastError();
int WSASetLastError(int iError);
}
这是我从中调用函数的代码:
public class TestWSAEnumProtocolsA {
public void start(){
WSAPROTOCOL_INFO wsaprotocol_info = new WSAPROTOCOL_INFO();
LPWSADATA lpwsaData = new LPWSADATA();
int lpdwBufferLength = -2;
int result = 0;
short version = 514;
if((result = Ws2_32.INSTANCE.WSAStartup(version, lpwsaData)) != 0){
System.out.println("Error #" + result + " at WSAStartup()");
return;
} else {
System.out.println("WSAStartup() finished correctly.");
if((result = Ws2_32.INSTANCE.WSAEnumProtocols(null, wsaprotocol_info, lpdwBufferLength)) == -1){
System.out.println("WSAEnumProtocolsW() returned: " + result);
System.out.println("lpdwBufferLength is: " + lpdwBufferLength);
System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
System.out.println("Now I'm setting it to 10004");
Ws2_32.INSTANCE.WSASetLastError(10004);
System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
}
}
}
}
该代码产生以下输出:
WSAStartup()正确完成。
WSAEnumProtocolsW()返回:-1
lpdwBufferLength为:-2
WSAGetLastError()返回:0
现在我将其设置为10004
WSAGetLastError()返回:0
这就是我定义调用这些函数时使用的结构的方式:
public class WinSock2_structs {
public static class LPWSADATA extends Structure{
public short wVersion;
public short wHighVersion;
public byte szDescription[] = new byte[256+1];
public byte szSystemStatus[] = new byte[128+1];
public short iMaxSockets;
public short iMaxUdpDg;
public char lpVendorInfo;
}
public static class WSAPROTOCOLCHAIN extends Structure{
public int ChainLen;
public int ChainEntries[] = new int[7];
}
public static class GUID extends Structure{
public int Data1;
public short Data2;
public short Data3;
public short Data4;
public byte Data5[] = new byte[8];
}
public static class WSAPROTOCOL_INFO extends Structure{
public int dwServiceFlags1;
public int dwServiceFlags2;
public int dwServiceFlags3;
public int dwServiceFlags4;
public int dwProviderFlags;
public GUID ProviderId;
public int dwCatalogEntryId;
public WSAPROTOCOLCHAIN ProtocolChain;
public int iVersion;
public int iAddressFamily;
public int iMaxSockAddr;
public int iMinSockAddr;
public int iSocketType;
public int iProtocol;
public int iProtocolMaxOffset;
public int iNetworkByteOrder;
public int iSecurityScheme;
public int dwMessageSize;
public int dwProviderReserved;
public char szProtocol[] = new char[256];
}
}
最佳答案
您两次调用WSAStartup()
,这将要求您两次调用WSACleanup()
才能正确卸载WinSock。您应该只调用一次WSAStartup()
。szProtocol
结构的WSAPROTOCOL_INFO
成员是TCHAR
元素的数组。 TCHAR
映射到char
或wchar_t
取决于调用应用程序是针对ANSI / MBCS还是UNICODE编译的。因此,ws2_32.dll中没有WSAEnumProtocols()
函数。相反,有单独的WSAEnumProtocolsA()
(对于Ansi)和WSAEnumProtocolsW()
(对于Unicode)函数。由于Java使用Unicode字符串,因此您应该使JNA代码使用WSAEnumProtocolsW()
。 WSAStartup()
不使用TCHAR
,仅使用char
,这就是为什么没有单独的WSAStartupA()
和WSAStartupW()
功能的原因。
如果您的JNA代码无法正确运行WSAEnumProtocols()
和WSAGetLastError()
,则可能是您在声明/错误使用它们,但是您没有显示任何代码,因此没有人可以确定为什么不为你工作。
更新:尝试这样的事情(我不使用JNA,因此可能需要进行一些调整,但这将为您提供总体思路):
public interface Ws2_32 extends Library {
// I don't know how to declare fixed size arrays in JNA,
// so you will have to adjust these Structue declarations
// as needed...
public static class WSAData extends Structure {
short wVersion;
short wHighVersion;
byte szDescription[257];
byte szSystemStatus[129];
short iMaxSockets;
short iMaxUdpDg;
String lpVendorInfo;
};
public static class WSAPROTOCOLCHAIN extends Structure {
int ChainLen;
int ChainEntries[7];
};
public static class WSAPROTOCOL_INFOW extends Structure {
int dwServiceFlags1;
int dwServiceFlags2;
int dwServiceFlags3;
int dwServiceFlags4;
int dwProviderFlags;
GUID ProviderId;
int dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
int dwMessageSize;
int dwProviderReserved;
char szProtocol[256];
};
Ws2_32 INSTANCE = (Ws2_32) Native.loadLibrary("ws2_32", Ws2_32.class);
int WSAStartup(short version, WSADATA lpwsaData);
int WSAEnumProtocolsW(int[] lpiProtocols, WSAPROTOCOL_INFOW[] lpProtocolBuffer, IntByReference lpdwBufferLength);
int WSACleanup();
int WSAGetLastError();
int WSASetLastError(int iError);
}
。
public static void main(String[] args){
WSADATA wsaData = new WSADATA();
short version = 2;
int result = Ws2_32.INSTANCE.WSAStartup(version, wsaData);
System.out.println("WSAStartup() returned: " + result);
if(result == 0){
System.out.println("WSADATA struct:");
System.out.println("wVersion: " + wsaData.wVersion);
System.out.println("wHighVersion: " + wsaData.wHighVersion);
System.out.print("szDescription: ");
for(byte b : wsaData.szDescription){
System.out.print((char) b);
}
System.out.print("\n");
System.out.print("szSystemStatus: ");
for(byte b : wsaData.szSystemStatus){
System.out.print((char) b);
}
System.out.print("\n");
System.out.println("iMaxSockets: " + wsaData.iMaxSockets);
System.out.println("iMaxUdpDg: " + wsaData.iMaxUdpDg");
}
}
。
public class TestWSAEnumProtocolsA {
public void start(){
WSAPROTOCOL_INFOW[] wsaprotocol_info = new WSAPROTOCOL_INFOW[1];
WSADATA wsaData = new WSADATA();
IntByReference dwBufferLength = new IntByReference(628); // sizeof WSAPROTOCOL_INFOW, in bytes
int result = 0;
short version = 2;
if((result = Ws2_32.INSTANCE.WSAStartup(version, wsaData)) != 0){
System.out.println("Error #" + result + " at WSAStartup()");
return;
}
System.out.println("WSAStartup() finished correctly.");
if((result = Ws2_32.INSTANCE.WSAEnumProtocolsW(null, wsaprotocol_info, dwBufferLength)) == -1){
System.out.println("WSAEnumProtocolsW() returned: " + result);
System.out.println("dwBufferLength is: " + dwBufferLength.getValue());
System.out.println("WSAGetLastError() returned: " + Ws2_32.INSTANCE.WSAGetLastError());
}
}
}