我正在编写setsockopt在JNA下的实现。Java本身就是支持setsockopt,但它并不支持所有特定于平台的套接字选项。例如,它不支持Linux下的[TCP_KEEPIDLE][2]。显然,这些选项中有许多不是很容易移植的,使用JNA是一条导致移植性差的途径;我知道这一点。请别告诉我这个主意太可怕了。
然而,我想做的是使我的代码比Linux下的代码更易于重用。我希望它能够(尽可能)在几个目标平台上工作。如果套接字选项不可用,则会引发异常。
我的挑战是这个。JNA运行良好,但是套接字选项的值在不同的平台上是不同的。例如,SO_RCVBUF在OS下是0x1002,在Linux下是8 (我知道SO_RCVBUF可以被普通的JavasetSockOpt控制--这是一个易于用lsof测试的例子)。SO_DONTROUTE在Linux下是5,在OS下是0x0010 (通过setSockOpt是无法控制的)。
所以我想要做的是取一个enum值来表示套接字选项(SO_SNDBUF,SO_RCVBUF或其他什么),然后在平台相关的映射中查找它,因此我在OS和8 / 5下获得了0x1002 / 0x010。
这很容易,但是我如何知道JNA下的平台是什么,这样我就知道要使用哪个地图了?JNA必须对自己的平台有某种感觉,否则它将不知道如何调用本地库。
package sockettest;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.Socket;
import com.sun.jna.LastErrorException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
public class JNASockOpt {
private static Field fdField;
static {
Native.register("c");
try {
fdField = FileDescriptor.class.getDeclaredField("fd");
fdField.setAccessible(true);
} catch (Exception ex) {
fdField = null;
}
}
public static int getInputFd(Socket s) {
try {
FileInputStream in = (FileInputStream)s.getInputStream();
FileDescriptor fd = in.getFD();
return fdField.getInt(fd);
} catch (Exception e) { }
return -1;
}
public static int getOutputFd(Socket s) {
try {
FileOutputStream in = (FileOutputStream)s.getOutputStream();
FileDescriptor fd = in.getFD();
return fdField.getInt(fd);
} catch (Exception e) { }
return -1;
}
public static int getFd(Socket s) {
int fd = getInputFd(s);
if (fd != -1)
return fd;
return getOutputFd(s);
}
// The list of SOL_ and SO_ options is platform dependent
public static final int SOL_SOCKET = 0xffff; // that's under OS-X, but it's 1 under Linux
public static final int SO_RCVBUF = 0x1002; // that's under OS-X, but it's 8 under Linux
public static final int SO_DONTROUTE = 0x0010; // that's under OS-X, but it's 5 under Linux
private static native int setsockopt(int fd, int level, int option_name, Pointer option_value, int option_len) throws LastErrorException;
public static void setSockOpt (Socket socket, int level, int option_name, int option_value) throws IOException {
if (socket == null)
throw new IOException("Null socket");
int fd = getFd(socket);
if (fd == -1)
throw new IOException("Bad socket FD");
IntByReference val = new IntByReference(option_value);
try {
setsockopt(fd, level, option_name, val.getPointer(), 4);
} catch (LastErrorException ex) {
throw new IOException("setsockopt: " + strerror(ex.getErrorCode()));
}
}
public static native String strerror(int errnum);
private JNASockOpt() {
}
}发布于 2015-03-16 20:31:12
JNA提供的类com.sun.jna.Platform由JNA本身使用,具有查询OS家族和CPU体系结构的功能。
isMac()和isLinux()有静态的方法。
https://stackoverflow.com/questions/29053320
复制相似问题