【问题标题】:JNI/C socket connection error on Solaris 11Solaris 11 上的 JNI/C 套接字连接错误
【发布时间】:2018-04-06 22:08:06
【问题描述】:

我们的应用程序使用了几个用 c 实现的套接字连接(到 localhost),其中一个连接使用 jni/c 套接字连接。它们都调用相同的 include 来打开套接字,当我们在 Solaris 10 上运行应用程序时,它们都成功了。 迁移到 Solaris 11,我们发现只有 c 中内置的套接字连接有效,一个 jni/c 连接不起作用。我添加了输出以查看究竟是什么被发送到连接调用,看起来调用正在获得它需要的一切:

"sock_connect: socket status: 0, sock_d: 27, serv_addr: ***.***.***.***, sizeof: 16"

So for the call below, sock_d = 27
                       serv_addr = (it returns a good IP, but my PM said he'd kill me if I put the actual IP) 
                       sizeof(serv_addr) = 16
which should be all the parameters connect() needs in the code snippet below.

.
.
.
.
status = connect(sock_d, (struct sockaddr *)&serv_addr, sizeof(serv_addr));

if (status < 0){
   fprintf(stderr, "sock_connect 4: after connect errno: %i, error %sn", errno, strerror(errno));
   if (errno == EINPROGRESS){
      fprintf(stderr, "sock_connect, errno == EINPROGRESS\n");
.
.
.

连接失败的Truss 输出似乎表明EINPROGRESS 错误。我们的代码应该验证这种可能性,但它不会触发 if 语句来检查 error == EINPROGRESS 是否存在。它永远不会到达第二个fprintf 语句。我们已经在服务器上禁用了 IPv6,因为我们认为 java 可能试图强制使用此协议,但这也没有什么不同。

完全相同的库和可执行文件将在两台服务器上运行,直到进行 jni 套接字调用。从那时起,Solaris 10 继续运行,但 Solaris 11 不会。

有人见过这个吗?请让我知道您还需要看什么,我会发布它。提前致谢!

【问题讨论】:

    标签: sockets java-native-interface solaris


    【解决方案1】:

    此代码错误地假定fprintf() 永远不会修改errno:

    if (status < 0){
       fprintf(stderr, "sock_connect 4: after connect errno: %i, error %sn", errno, strerror(errno));
       if (errno == EINPROGRESS){
          fprintf(stderr, "sock_connect, errno == EINPROGRESS\n");
    

    POSIX standard for errno 状态(强调我的):

    errno 的值只能在调用明确声明要设置的函数之后定义,直到它被下一个函数调用更改或者如果应用程序分配它是一个值。

    并且根据Solaris 11.3 fprintf() man page,fprintf()可以设置errno:

    错误

    对于printf()、fprintf() 和 dprintf() 会失败,也可能失败,参考 fputc(3C) 或 fputwc(3C)。

    snprintf() 函数将在以下情况下失败:

    EOVERFLOW

    n 的值大于 INT_MAX 或需要的字节数 保持输出不包括终止空值大于 INT_MAX。

    所有形式的printf() 在以下情况下都会失败:

    EILSEQ

    与有效字符不对应的宽字符代码 已被检测到。

    EINVAL

    论据不足。

    dprintf() 函数将在以下情况下失败:

    EBADF

    fildes 参数不是有效的文件描述符。

    printf()、fprintf()、dprintf() 和 asprintf() 函数 如果出现以下情况,可能会因潜在的malloc(3C) 失败而失败:

    EAGAIN

    存储空间暂时不可用。

    ENOMEM

    可用存储空间不足。

    【讨论】:

    • 好的,我删除了 fprintf 语句,但仍然有相同的结果。尽管 truss 输出指示 EINPROGRESS 错误,它仍然绕过 EINPROGRESS 错误:3699/24: so_socket(PF_INET6, SOCK_STREAM, IPPROTO_IP, 0, SOV_DEFAULT) = 7 3699/2: connect(6, 0xFE01F854, 16, SOV_DEFAULT) Err#150 EINPROGRESS 3699/24: getsockname(0, 0xB611DAE4, 0xB611DB04, SOV_DEFAULT) Err#95 ENOTSOCK
    • @user9608801 然后还有其他问题。但是如果没有一个完整的例子可以用来复制你的问题,这是不可能的。问题出在 Solaris 11 而不是您的代码中的可能性非常非常低。我会首先寻找做一些愚蠢的事情的人,比如重新定义errno(对系统对errno 宏的定义执行anything会导致未定义的行为......)。你也可以只预处理你的代码,而不是一路编译,看看是否有一些宏把事情搞砸了。
    猜你喜欢
    • 2011-07-31
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 2014-01-26
    • 1970-01-01
    • 2019-06-20
    相关资源
    最近更新 更多