首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在JNA下为setsockopt确定平台

在JNA下为setsockopt确定平台
EN

Stack Overflow用户
提问于 2015-03-14 19:37:14
回答 1查看 594关注 0票数 0

我正在编写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_SNDBUFSO_RCVBUF或其他什么),然后在平台相关的映射中查找它,因此我在OS和8 / 5下获得了0x1002 / 0x010

这很容易,但是我如何知道JNA下的平台是什么,这样我就知道要使用哪个地图了?JNA必须对自己的平台有某种感觉,否则它将不知道如何调用本地库。

代码语言:javascript
复制
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() {
    }
}
EN

回答 1

Stack Overflow用户

发布于 2015-03-16 20:31:12

JNA提供的类com.sun.jna.Platform由JNA本身使用,具有查询OS家族和CPU体系结构的功能。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29053320

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档