java - 确定 JNA 下的 setsockopt 平台

标签 java sockets jna

我正在编写 setsockopt 的实现在 JNA 下。 Java本身supports setsockopt ,但它不支持所有特定于平台的套接字选项。例如,它不支持 [TCP_KEEPIDLE][2]在Linux下。显然,其中许多选项的可移植性不太好,而使用 JNA 会导致可移植性较差;我知道这一点。请不要费心告诉我这个想法非常可怕。

然而,我想做的是让我的代码比只在 Linux 下运行的代码更具可重用性。我希望它能够(尽可能)在多个目标平台上工作。如果套接字选项不可用,它可能会抛出异常。

我的挑战是这样的。 JNA 工作正常,但套接字选项的值在不同平台上有所不同。例如,SO_RCVBUF0x1002在 OS-X 和 8 下在Linux下(我意识到 SO_RCVBUF 可以由普通的Java setSockOpt 控制 - 这是一个很容易使用 lsof 进行测试的示例)。 SO_DONTROUTE5在 Linux 下,和 0x0010在 OS-X 下(并且不能通过 Java setSockOpt 控制)。

所以我想要它做的是采取 enum代表套接字选项的值( SO_SNDBUFSO_RCVBUF 或其他),并在平台相关映射中查找该值,所以我得到 0x1002/0x010在 OS-X 和 8 下/5 Linux 下。

这很简单,但是我如何知道 JNA 下的平台是什么,以便我知道要使用哪个 map ? JNA 必须以某种方式了解自己的平台,否则(我认为)它不知道如何调用 native 库。

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() {
    }
}

最佳答案

类(class)com.sun.jna.Platform JNA提供的供JNA本身使用,具有查询操作系统家族和CPU架构的功能。

isMac()isLinux() 的静态方法。

关于java - 确定 JNA 下的 setsockopt 平台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29053320/

相关文章:

python - 确定 TCP listen() 队列中当前积压的连接数

c - 如何使用服务器上的 fork 子进程重用打开的客户端连接(TCP/IP 套接字)

java - 使用 Selenium Java 从 HTML 中获取字符串文本

c# - 如何在 Eclipse for Java 中为 Web 服务创建 "proxy"类?

sockets - nodejs中的套接字

java - 使用 Java JNA 调用 DLL 库

java - JNA 和结构体数组作为参数

java - .jar 文件无法正常工作

java - 用于制作和检查 5's,3' 的编号或两者的组合的输出未按预期获得?

java - JNA 指针检索值