Linux 和 Solaris 中的 setsockopt 用法 [Solaris 中的参数无效]

setsockopt usage in Linux and Solaris [Invalid argument in Solaris]

我正在尝试在我的 ftp 程序中同时在 Linux 和 Solaris 上使用 setsockopt()

Linux 对 optvalue 使用 long 作为参数,但 Solaris 使用 char 作为参数。

#ifdef sun
    char val;
#else
    long val;
#endif

#ifdef sun
    val = 1;
    size_t len = sizeof(char);
    if(setsockopt(s_socket_fd, SOL_SOCKET, SO_REUSEADDR, &val, len) == -1) {
        perror("Fail");
        exit(1);
    }
#else
    val = 1;
    size_t len = sizeof(long);
    if(setsockopt(s_socket_fd, SOL_SOCKET, SO_REUSEADDR, &val, len) == -1) {
        perror("Fail");
        exit(1);
    }
#endif

该程序在 Linux 中运行良好,但在创建套接字时在 Solaris 中报告 "Invalid argument"。

题目中出现了2个问题:

  • Linux uses a long for optvalue as a parameter, but Solaris uses a char instead.

TL;DR:你应该在所有地方使用 int

在 Solaris 中,setsockopt() 的定义可能略有不同,具体取决于 Solaris 的版​​本和程序所链接的库,例如 Solaris 10 的 setsockopt (3SOCKET), setsockopt (3XNET) and Solaris 11's setsockopt (3SOCKET), setsockopt (3XNET). Linux' manpage 与 Solaris 共享相同的内容(3SOCKET) 联机帮助页:

Most socket-level options utilize an int argument for optval. For setsockopt(), the argument should be nonzero to enable a boolean option, or zero if the option is to be disabled.

(3XNET) 只是没有说明布尔选项的类型。 Yet-an-other-UNIX (AIX) 也有旧的 *BSD 和 UNIX98/XOPEN 版本,在 single page, where it's an int for booleans. The confusion about using char comes from (*BSD-style) examples using a pointer cast to (char *) instead of (const void *), because the prototype is using char * for *BSD/3XNET. That doesn't mean the parameter is char. As for long, beside not being in the definition, on architectures where long is not int 上是错误的。请注意 Windows 与 *NIX 不同。

  • size_t len = sizeof(char);
    

除了 sizeof val 应该是首选,并且可以直接在 setsockopt() 中使用,甚至不需要首先在这里使用 lenlen 在 Solaris (3XNET) 上定义为 int,在 Solaris (3SOCKET) 上定义为 socklen_t,在任何地方都定义为 Linux,而不是 size_tLink to a possible explanation 关于为什么 int 变成了 socklen_t,通过 size_t 的简短(错误)段落。当 size_t 未定义为 int 时,使用其他类型(例如 Linux 上的 size_t)可能会在某些体系结构上中断(请参阅前面的 2 个链接)。