getsockopt 函数 (winsock.h)

getsockopt 函数检索套接字选项。

语法

int getsockopt(
  [in]      SOCKET s,
  [in]      int    level,
  [in]      int    optname,
  [out]     char   *optval,
  [in, out] int    *optlen
);

参数

[in] s

标识套接字的描述符。

[in] level

定义选项的级别。 示例: SOL_SOCKET

[in] optname

要为其检索值的套接字选项。 示例: SO_ACCEPTCONNoptname 值必须是在指定级别内定义的套接字选项,否则行为未定义。

[out] optval

一个指向缓冲区的指针,在该缓冲区中,将返回所请求的选项的值。

[in, out] optlen

指向 optval 缓冲区的大小(以字节为单位)的指针。

返回值

如果未发生错误, 则 getsockopt 返回零。 否则,将返回值 SOCKET_ERROR,并且可以通过调用 WSAGetLastError 检索特定的错误代码。

错误代码 含义
WSANOTINITIALIZED
在使用此函数之前,必须成功调用 WSAStartup
WSAENETDOWN
注意 网络子系统发生故障。
 
WSAEFAULT
optvaloptlen 参数之一不是用户地址空间的有效部分,或者 optlen 参数太小。
WSAEINPROGRESS
阻止 Windows 套接字 1.1 调用正在进行,或者服务提供商仍在处理回调函数。
WSAEINVAL
级别参数未知或无效。
WSAENOPROTOOPT
选项未知或不受所指示的协议系列支持。
WSAENOTSOCK
:描述符不是套接字。

注解

getsockopt 函数检索与任何类型、处于任何状态的套接字关联的套接字选项的当前值,并将结果存储在 optval 中。 选项可以存在于多个协议级别,但它们始终存在于最上面的套接字级别。 选项会影响套接字操作,例如数据包路由和 OOB 数据传输。

与所选选项关联的值在缓冲区 optval 中返回。 optlen 指向的整数最初应包含此缓冲区的大小;返回时,它将设置为返回的值的大小。 对于SO_LINGER,这是 LINGER 结构的大小。 对于大多数其他选项,它将是整数的大小。

应用程序负责分配由它指定的任何参数直接或间接指向的任何内存空间。

如果从未使用 setockopt 设置选项,则 getsockopt 返回选项的默认值。

getsockopt 支持以下选项。 “类型”列标识 optval 寻址的数据类型。

有关套接字选项的详细信息,请参阅 套接字选项

level 参数设置为 SOL_SOCKET 时,optname 参数的值表有效。

类型 含义
SO_ACCEPTCONN BOOL 套接字正在侦听。
SO_BROADCAST BOOL 套接字配置为用于传输和接收广播消息。
SO_BSP_STATE CSADDR_INFO 返回套接字使用的本地地址、本地端口、远程地址、远程端口、套接字类型和协议。
SO_CONDITIONAL_ACCEPT BOOL 从上一次调用 setsockopt 或系统默认值返回当前套接字状态。
SO_CONNECT_TIME DWORD 返回已连接套接字的秒数。 此套接字选项仅适用于面向连接的协议。
SO_DEBUG BOOL 已启用调试。
SO_DONTLINGER BOOL 如果 为 TRUE,则禁用SO_LINGER选项。
SO_DONTROUTE BOOL 路由功能被禁用。 此设置成功,但在AF_INET套接字上将被忽略;使用 WSAENOPROTOOPT AF_INET6套接字失败。 ATM 套接字不支持此选项。
SO_ERROR int 检索错误状态并清除。
SO_EXCLUSIVEADDRUSE BOOL 阻止任何其他套接字绑定到同一地址和端口。 在调用 绑定 函数之前,必须设置此选项。
SO_GROUP_ID GROUP 保留。
SO_GROUP_PRIORITY int 保留。
SO_KEEPALIVE BOOL 正在发送“保持连接”。 ATM 套接字不支持。
SO_LINGER LINGER 结构 返回当前的逗留选项。
SO_MAX_MSG_SIZE unsigned int 面向消息的套接字类型的消息的最大大小 (例如,SOCK_DGRAM) 。 对于面向流的套接字没有意义。
SO_OOBINLINE BOOL 正在正常数据流中接收 OOB 数据。 (有关本主题的讨论,请参阅 Windows 套接字 1.1 阻止例程和 EINPROGRESS 部分。)
SO_PORT_SCALABILITY BOOL 通过为本地计算机上的不同本地地址端口对多次分配通配符端口,允许最大化端口分配,从而为套接字启用本地端口可伸缩性。
SO_PROTOCOL_INFO WSAPROTOCOL_INFO 绑定到此套接字的协议的协议信息的说明。
SO_RCVBUF int 为接收保留的每个套接字的总缓冲区空间。 这与SO_MAX_MSG_SIZE无关,也不一定对应于 TCP 接收窗口的大小。
SO_REUSEADDR BOOL 可以将套接字绑定到已在使用中的地址。 不适用于 ATM 插座。
SO_SNDBUF int 为发送保留的每个套接字缓冲区总空间。 这与SO_MAX_MSG_SIZE无关,也不一定对应于 TCP 发送窗口的大小。
SO_TYPE int 套接字的类型 (例如,SOCK_STREAM) 。
PVD_CONFIG 服务提供程序依赖 套接字关联的服务提供程序中的不透明数据结构对象。 此对象存储服务提供程序的当前配置信息。 此数据结构的确切格式特定于服务提供程序。
 

水平 = IPPROTO_TCP

请参阅IPPROTO_TCP套接字选项中的TCP_NODELAY。 有关 级别 = IPPROTO_TCP的套接字选项的更完整和详细信息,另请参阅该主题。  

level 参数设置为 NSPROTO_IPX 时,optname 参数的以下值表有效。

注意 Windows NT 支持所有 IPX 选项。 Windows Me、Windows 98 和 Windows 95 仅支持以下选项:
IPX_PTYPE
IPX_FILTERPTYPE
IPX_DSTYPE
IPX_RECVHDR
IPX_MAXSIZE
IPX_ADDRESS
 
类型 含义
IPX_PTYPE int 检索 IPX 数据包类型。
IPX_FILTERPTYPE int 检索接收筛选器数据包类型
IPX_DSTYPE int 获取发送的每个数据包的 SPX 标头中数据流字段的值。
IPX_EXTENDED_ADDRESS BOOL 了解是否启用了扩展寻址。
IPX_RECVHDR BOOL 了解是否在所有接收标头上发送协议标头。
IPX_MAXSIZE int 获取可发送的最大数据大小。
IPX_ADDRESS IPX_ADDRESS_DATA 结构 获取有关 IPX 绑定到的特定适配器的信息。 适配器编号以零为底。 返回时将填充 adapternum 成员。
IPX_GETNETINFO IPX_NETNUM_DATA 结构 获取有关特定 IPX 网络编号的信息。 如果缓存中不可用,请使用 RIP 获取信息。
IPX_GETNETINFO_NORIP IPX_NETNUM_DATA 结构 获取有关特定 IPX 网络编号的信息。 如果缓存中不可用,则 不会使用 RIP 获取信息,并返回错误。
IPX_SPXGETCONNECTIONSTATUS IPX_SPXCONNSTATUS_DATA 结构 检索有关连接的 SPX 套接字的信息。
IPX_ADDRESS_NOTIFY IPX_ADDRESS_DATA 结构 检索 IPX 绑定到的适配器上发生更改时的状态通知。
IPX_MAX_ADAPTER_NUM int 检索存在的最大适配器数,编号为基数零。
IPX_RERIPNETNUMBER IPX_NETNUM_DATA 结构 类似于 IPX_GETNETINFO,但强制 IPX 使用 RIP 进行解析,即使网络信息位于本地缓存中也是如此。
IPX_IMMEDIATESPXACK BOOL 指示 SPX 连接在发送 ACK 之前不要延迟。 没有来回流量的应用程序应将此设置为 TRUE 以提高性能。
TCP_MAXSEG int 接收 TCP 最大段大小。 在 Windows 10 和更新版本中受支持。
 

下表列出了表示 getsockopt 函数不支持的 BSD 套接字选项的 optname 的值。

类型 含义
SO_RCVLOWAT int 接收低水印。
SO_RCVTIMEO int 接收超时。
SO_SNDLOWAT int 发送低水印。
SO_SNDTIMEO int 发送超时。
TCP_MAXSEG int 接收 TCP 最大段大小。 在Windows 10之前的版本中不受支持。
 
注意 使用 recv 函数时,如果在 SO_RCVTIMEO 中指定的时间段内没有数据到达, 则 recv 函数完成。 在 Windows 2000 之前的 Windows 版本中,接收的任何数据随后都失败并出现 WSAETIMEDOUT。 在 Windows 2000 及更高版本中,如果在 SO_RCVTIMEO 中指定的时间段内没有数据到达, 则 recv 函数将返回 WSAETIMEDOUT,如果收到数据, recv 将返回 SUCCESS。
 

使用不支持的选项调用 getockopt 将导致从 WSAGetLastError 返回 WSAENOPROTOOPT错误代码。

下面列出了有关 getsockopt 函数支持的 optname 参数的一些套接字选项的详细信息。

SO_CONNECT_TIME
此选项返回已连接套接字的秒数。 此选项仅适用于面向连接的协议。

SO_CONNECT_TIME 选项可与 getsockopt 函数一起使用,以检查是否已建立连接。 当 ConnectEx 函数调用正在进行时,也可以使用此选项。 如果已建立连接,SO_CONNECT_TIME选项可以确定建立连接的时间。 如果未连接套接字, 则 getsockopt 返回SOCKET_ERROR。 需要检查这样的连接,以查看是否已建立一段时间的连接,而无需发送任何数据。 建议应用程序终止这些连接。

SO_DEBUG
注意 如果应用程序设置了SO_DEBUG选项,则建议 Windows 套接字服务提供商 (但不要求) 提供输出调试信息。 生成调试信息的机制及其采用的形式超出了本文档的范围。
 
SO_ERROR
SO_ERROR 选项返回并重置每个套接字的错误代码,这与使用 WSAGetLastErrorWSASetLastError 函数调用处理的基于线程的错误代码不同。 使用套接字的成功调用不会重置 SO_ERROR 选项返回的基于套接字的错误代码。
SO_EXCLUSIVEADDRUSE
阻止任何其他套接字绑定到同一地址和端口。 在调用 绑定 函数之前,必须设置此选项。 有关详细信息,请参阅 SO_EXCLUSIVEADDRUSE 参考。
SO_GROUP_ID
注意 此选项是保留的。 此选项也是 getsockopt 独有的;值应为 NULL
 
SO_GROUP_PRIORITY
此选项是保留的。 组优先级指示指定套接字相对于套接字组内其他套接字的优先级。 值是非否定整数,零对应于最高优先级。 优先级值表示基础服务提供商关于应如何分配潜在稀缺资源的提示。 例如,每当两个或更多个套接字都准备好传输数据时,应首先为SO_GROUP_PRIORITY) 的最高优先级套接字 (最低值提供服务,其余套接字根据其相对优先级依次提供服务。

对于非组套接字或不支持组套接字的服务提供程序,指示 WSAENOPROTOOPT 错误代码。

SO_KEEPALIVE
应用程序可以通过打开“SO_KEEPALIVE套接字”选项,请求 TCP/IP 服务提供商允许在 TCP 连接上使用保持连接数据包。 此选项查询套接字上 keep-alive 选项的当前值。 Windows 套接字提供程序不需要支持使用 keep-alive:如果支持,则精确的语义是特定于实现的,但应符合 IETF 网站上 RFC 1122 中指定的 Internet 主机要求 (RFC 1122 中指定的通信层)中的 4.2.3.6 部分。 如果由于保持连接而断开连接,则错误代码 WSAENETRESET 将返回到套接字上正在进行的任何调用,并且任何后续调用都将失败, WSAENOTCONNSO_KEEPALIVE 在 ATM 套接字上不受支持,并且请求在 ATM 套接字上启用保持连接数据包会导致套接字返回错误。
SO_LINGER
SO_LINGER控制未发送的数据在套接字上排队并执行 closesocket 时执行的操作。 有关SO_LINGER设置影响 closesocket 语义的方式的说明,请参阅 closesocket。 应用程序通过检索 optval 参数) 指向 (LINGER 结构来获取当前行为。
SO_MAX_MSG_SIZE
这是一个仅限获取的套接字选项,指示针对面向消息的套接字类型发送消息的最大出站 () 大小 (,例如,SOCK_DGRAM) 由特定服务提供商实现。 它对于面向字节流的套接字没有意义。 没有用于找出最大入站消息大小的预配。
SO_PROTOCOL_INFO
这是一个仅获取选项,可提供与此套接字关联的 WSAPROTOCOL_INFO 结构。 有关此结构的详细信息,请参阅 WSAEnumProtocols
SO_SNDBUF
当 Windows 套接字实现支持SO_RCVBUF和SO_SNDBUF选项时,应用程序可以请求不同的缓冲区大小 (更大或更小) 。 即使实现未提供请求的全部数量,对 setsockopt 的调用也会成功。 应用程序必须使用相同的选项调用此函数,以检查实际提供的缓冲区大小。
SO_REUSEADDR
默认情况下,无法绑定套接字, (看到 绑定到 已使用的本地地址) 。 但是,有时可能需要以这种方式重用地址。 由于每个连接都是由本地地址和远程地址组合唯一标识的,因此,只要远程地址不同,将两个套接字绑定到同一本地地址就没有问题。 若要通知 Windows 套接字提供程序不应禁止某个套接字上的 绑定 ,因为所需的地址已被另一个套接字使用,应用程序应在发出 绑定之前为套接字设置SO_REUSEADDR套接字选项。 请注意,选项仅在 绑定时被解释:因此,在不绑定到现有地址的套接字上设置选项是不必要的 (但无害的) ,并在 绑定 后设置或重置选项对此或任何其他套接字没有影响。 SO_REUSEADDR不适用于 ATM 套接字,尽管重复使用和地址的请求不会导致错误,但它们对使用 ATM 套接字时没有影响。
PVD_CONFIG
此选项从 与套接字关联的服务提供程序检索不透明的数据结构对象。 此对象存储服务提供程序的当前配置信息。 此数据结构的确切格式特定于服务提供商。
TCP_NODELAY
TCP_NODELAY选项特定于 TCP/IP 服务提供商。 如果启用TCP_NODELAY选项 (,则禁用 Nagle 算法,反之亦然) 。 RFC 896) 中所述的 Nagle 算法 (在减少主机发送的小数据包数量方面非常有效。 此过程涉及在尚未确认的数据处于未确认状态时缓冲发送数据,或缓冲发送数据,直到可以发送完整大小的数据包。 强烈建议 Windows 套接字实现默认启用 Nagle 算法,因为对于绝大多数应用程序协议,Nagle 算法可以提供显著的性能增强。 但是,对于某些应用程序,此算法可能会降低性能,并且可以使用具有相同选项的 setsockopt 将其关闭。 这些应用程序发送了许多小消息,并维护消息之间的时间延迟。
注意 发出阻止的 Winsock 调用(如 getsockopt)时,Winsock 可能需要等待网络事件,然后调用才能完成。 在这种情况下,Winsock 执行可发出警报的等待, (在同一线程上计划的 APC) 异步过程调用可能会中断。 在 APC 内发出另一个阻止 Winsock 调用,该调用中断了同一线程上正在进行的阻止 Winsock 调用将导致未定义的行为,并且 Winsock 客户端绝不能尝试。
 

示例代码

以下代码示例演示如何使用 getsockopt 函数。
#include <stdio.h>
#include "winsock2.h"
#include <windows.h>

void main() {

  //---------------------------------------
  // Declare variables
  WSADATA wsaData;
  SOCKET ListenSocket;
  sockaddr_in service;

  //---------------------------------------
  // Initialize Winsock
  int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
  if( iResult != NO_ERROR )
    printf("Error at WSAStartup\n");

  //---------------------------------------
  // Create a listening socket
  ListenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  if (ListenSocket == INVALID_SOCKET) {
    printf("Error at socket()\n");
    WSACleanup();
    return;
  }

  //---------------------------------------
  // Bind the socket to the local IP address
  // and port 27015
  hostent* thisHost;
  char* ip;
  u_short port;
  port = 27015;
  thisHost = gethostbyname("");
  ip = inet_ntoa (*(struct in_addr *)*thisHost->h_addr_list);

  service.sin_family = AF_INET;
  service.sin_addr.s_addr = inet_addr(ip);
  service.sin_port = htons(port);
 
  if ( bind( ListenSocket,(SOCKADDR*) &service, sizeof(service) )  == SOCKET_ERROR ) {
    printf("bind failed\n");
    closesocket(ListenSocket);
    return;
  }

  //---------------------------------------
  // Initialize variables and call getsockopt. 
  // The SO_ACCEPTCONN parameter is a socket option 
  // that tells the function to check whether the 
  // socket has been put in listening mode or not. 
  // The various socket options return different
  // information about the socket. This call should
  // return 0 to the optVal parameter, since the socket
  // is not in listening mode.
  int optVal;
  int optLen = sizeof(int);

  if (getsockopt(ListenSocket, 
    SOL_SOCKET, 
    SO_ACCEPTCONN, 
    (char*)&optVal, 
    &optLen) != SOCKET_ERROR)
    printf("SockOpt Value: %ld\n", optVal);

  //---------------------------------------
  // Put the listening socket in listening mode.
  if (listen( ListenSocket, 100 ) == SOCKET_ERROR) {
    printf("error listening\n");
  } 

  //---------------------------------------
  // Call getsockopt again to verify that 
  // the socket is in listening mode.
  if (getsockopt(ListenSocket, 
    SOL_SOCKET, 
    SO_ACCEPTCONN, 
    (char*)&optVal, 
    &optLen) != SOCKET_ERROR)
    printf("SockOpt Value: %ld\n", optVal);

  WSACleanup();
  return;
}

IrDA 套接字说明

  • 必须显式包含 Af_irda.h 头文件。
  • Windows 返回 WSAENETDOWN 以指示基础收发器驱动程序未能使用 IrDA 协议堆栈进行初始化。
  • IrDA 支持几个特殊的套接字选项:
    类型 含义
    IRLMP_ENUMDEVICES *DEVICELIST 描述范围内的设备。
    IRLMP_IAS_QUERY *IAS_QUERY 检索 IAS 属性。
     

在启动 IrDA 套接字连接之前,必须通过执行 getsockopt (,IRLMP_ENUMDEVICES,) 函数调用来获取设备地址,这会返回所有可用的 IrDA 设备的列表。 从函数调用返回的设备地址将复制到 SOCKADDR_IRDA 结构中,后者又由 对 connect 函数调用的后续调用使用。

可以通过两种方式执行发现:

  1. 首先,使用 IRLMP_ENUMDEVICES 选项执行 getsockopt 函数调用会导致在每个空闲适配器上运行单个发现。 ) 活动适配器上 (已发现设备和缓存设备的列表会立即返回。

    以下代码演示了此方法。

    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <af_irda.h>
    #include <stdio.h>
    #include <windows.h>
    
    // link with Ws2_32.lib
    
    int __cdecl main()
    {
    
        //-----------------------------------------
        // Declare and initialize variables
        WSADATA wsaData;
    
        int iResult;
        int i;
        DWORD dwError;
    
        SOCKET Sock = INVALID_SOCKET;
    
    #define DEVICE_LIST_LEN    10
    
    
        SOCKADDR_IRDA DestSockAddr = { AF_IRDA, 0, 0, 0, 0, "SampleIrDAService" };
    
        unsigned char DevListBuff[sizeof (DEVICELIST) -
                                  sizeof (IRDA_DEVICE_INFO) +
                                  (sizeof (IRDA_DEVICE_INFO) * DEVICE_LIST_LEN)];
    
        int DevListLen = sizeof (DevListBuff);
        PDEVICELIST pDevList;
    
        pDevList = (PDEVICELIST) & DevListBuff;
    
        // Initialize Winsock
        iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (iResult != 0) {
            printf("WSAStartup failed: %d\n", iResult);
            return 1;
        }
    
        Sock = socket(AF_IRDA, SOCK_STREAM, 0);
        if (Sock == INVALID_SOCKET) {
            dwError = WSAGetLastError();
            printf
                ("socket failed trying to create an AF_IRDA socket with error %d\n",
                 dwError);
    
            if (dwError == WSAEAFNOSUPPORT) {
                printf("Check that the local computer has an infrared device\n");
                printf
                    ("and a device driver is installed for the infrared device\n");
            }
            WSACleanup();
            return 1;
        }
        // Sock is not in connected state
        iResult = getsockopt(Sock, SOL_IRLMP, IRLMP_ENUMDEVICES,
                             (char *) pDevList, &DevListLen);
        if (iResult == SOCKET_ERROR) {
            printf("getsockopt failed with error %d\n", WSAGetLastError());
            WSACleanup();
            return 1;
        }
    
        if (pDevList->numDevice == 0) {
            // no devices discovered or cached
            // not a bad idea to run a couple of times
            printf("No IRDA devices were discovered or cached\n");
        } else {
            // one per discovered device
            for (i = 0; i < (int) pDevList->numDevice; i++) {
                // typedef struct _IRDA_DEVICE_INFO
                // {
                //     u_char    irdaDeviceID[4];
                //     char      irdaDeviceName[22];
                //     u_char    irdaDeviceHints1;
                //     u_char    irdaDeviceHints2;
                //     u_char    irdaCharSet;
                // } _IRDA_DEVICE_INFO;
    
                // pDevList->Device[i]. see _IRDA_DEVICE_INFO for fields
                // display the device names and let the user select one
            }
        }
    
        // assume the user selected the first device [0]
        memcpy(&DestSockAddr.irdaDeviceID[0], &pDevList->Device[0].irdaDeviceID[0],
               4);
    
        iResult = connect(Sock, (const struct sockaddr *) &DestSockAddr,
                          sizeof (SOCKADDR_IRDA));
        if (iResult == SOCKET_ERROR) {
            printf("connect failed with error %d\n", WSAGetLastError());
        } else
            printf("connect to first IRDA device was successful\n");
    
        WSACleanup();
        return 0;
    }
    
    
  2. 执行 IrDA 设备地址发现的第二种方法是执行延迟发现;在此方法中,在发现的设备列表与堆栈运行的最后一次发现发生更改之前,应用程序不会收到通知。
上表中的“类型”列中显示的 DEVICELIST 结构是可扩展的设备说明数组。 IrDA 会填充指定缓冲区中可容纳的任意数量的设备说明。 设备说明由构成sockaddr_irda结构所需的设备标识符和描述设备的可显示字符串组成。

上表中“类型”列中显示的 IAS_QUERY 结构用于从对等设备的 IAS 数据库中检索单个类的单个属性。 应用程序指定要查询的设备和类以及属性和属性类型。 请注意,设备之前是通过调用 getsockopt (IRLMP_ENUMDEVICES) 获取的。 预期应用程序会为返回的参数分配一个具有所需大小的缓冲区。

许多级别套接字选项对 IrDA 没有意义;仅专门支持SO_LINGER和SO_DONTLINGER。

Windows Phone 8:Windows Phone 8 及更高版本上的 Windows Phone 应用商店应用支持此函数。

Windows 8.1Windows Server 2012 R2:Windows 8.1、Windows Server 2012 R2 及更高版本的 Windows 应用商店应用支持此函数。

要求

要求
最低受支持的客户端 Windows 8.1,Windows Vista [桌面应用 |UWP 应用]
最低受支持的服务器 Windows Server 2003 [桌面应用 | UWP 应用]
目标平台 Windows
标头 winsock.h (包括 Winsock2.h)
Library Ws2_32.lib
DLL Ws2_32.dll

另请参阅

IPPROTO_IP套接字选项

IPPROTO_IPV6套接字选项

IPPROTO_RM套接字选项

IPPROTO_TCP套接字选项

IPPROTO_UDP套接字选项

NSPROTO_IPX套接字选项

SOL_APPLETALK套接字选项

SOL_IRLMP套接字选项

SOL_SOCKET套接字选项

套接字选项

WSAAsyncSelect

WSAConnect

WSAGetLastError

WSAIoctl

WSASetLastError

Winsock 函数

ioctlsocket

recv

setsockopt

socket