这是一个在 Linux/Unix 网络编程中非常核心和常用的函数。

getsockopt 是什么?
getsockopt 是 "get socket options" 的缩写,中文意思是“获取套接字选项”。
它的主要作用是查询和获取一个已创建的套接字(socket)的当前配置参数,这些参数被称为“套接字选项”(Socket Options),它们可以控制套接字的各种行为,
- 是否启用 TCP 的 Nagle 算法(
TCP_NODELAY)。 - 设置发送或接收缓冲区的大小(
SO_SNDBUF,SO_RCVBUF)。 - 获取套接字的本地地址和端口(
SO_ERROR)。 - 获取套接字所关联的协议族(
SO_DOMAIN)。 - 设置是否允许地址重用(
SO_REUSEADDR)。
getsockopt 与 setsockopt 是一对函数,后者用于设置套接字选项。
函数原型
getsockopt 在 <sys/socket.h> 头文件中声明。

#include <sys/socket.h> int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
参数详解
让我们逐个分析这个函数的五个参数:
| 参数 | 类型 | 描述 |
|---|---|---|
sockfd |
int |
套接字文件描述符,这是一个通过 socket() 函数创建,并通过 bind(), listen(), connect() 等函数使用过的、有效的套接字描述符,你想查询的就是这个套接字的选项。 |
level |
int |
选项级别,这个参数指定了选项所对应的协议层,常见的值有: • SOL_SOCKET: 通用套接字选项,适用于所有类型的套接字(无论 TCP, UDP, 还是原始套接字)。• IPPROTO_IP: IP 协议层选项。IP_TOS (服务类型)。• IPPROTO_TCP: TCP 协议层选项。TCP_NODELAY (禁用 Nagle 算法)。• IPPROTO_IPV6: IPv6 协议层选项。 |
optname |
int |
选项名称,这是一个具体的常量,它和 level 一起唯一确定了一个要查询的选项,当 level 是 SOL_SOCKET 时,optname 可以是 SO_REUSEADDR;当 level 是 IPPROTO_TCP 时,optname 可以是 TCP_NODELAY。 |
optval |
void * |
选项值的缓冲区,这是一个指向变量的指针,用于存放获取到的选项值,如果查询 SO_REUSEADDR,optval 就应该指向一个 int 类型的变量,如果查询 SO_RCVBUF,optval 也应指向一个 int。 |
optlen |
socklen_t * |
选项值缓冲区的长度,这是一个指向 socklen_t 类型变量的指针。它有两个作用:1. 输入:在调用 getsockopt 之前,你需要将 *optlen 设置为你为 optval 分配的缓冲区的大小(对于 int 类型,设置为 sizeof(int))。2. 输出:函数成功返回后, *optlen 会被修改为实际返回的选项值的长度,这对于某些可能返回变长数据的选项非常重要。 |
返回值
- 成功:返回
0。 - 失败:返回
-1,并设置errno来指示具体的错误原因,常见的errno包括:EBADF:sockfd不是一个有效的文件描述符。ENOPROTOOPT: 指定的level或optname不支持或不适用于该套接字。EFAULT:optval或optlen指向了不可访问的内存区域。EINVAL:optlen无效(指向的值为负数)。
使用示例
下面我们通过几个最常见的例子来演示如何使用 getsockopt。
示例 1:获取 TCP_NODELAY 选项
TCP_NODELAY 用于禁用 Nagle 算法,Nagle 算法会小数据包缓冲合并后发送,以减少网络报文数量,但对于需要低延迟的应用(如实时游戏、金融交易),我们希望数据包能立即发送。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
int flag = 0; // 用于存放获取到的值
socklen_t len = sizeof(flag); // 必须初始化为缓冲区大小
// 获取 TCP_NODELAY 选项
// IPPROTO_TCP 是 TCP 协议层
// TCP_NODELAY 是选项名
if (getsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, &len) < 0) {
perror("getsockopt failed");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("TCP_NODELAY option value: %d\n", flag);
printf("Length of the value returned: %zu\n", len);
close(sockfd);
return 0;
}
编译和运行:

gcc getsockopt_example1.c -o getsockopt_example1 ./getsockopt_example1
可能输出:
TCP_NODELAY option value: 0
Length of the value returned: 4
0 表示 Nagle 算法是启用的(默认值),你可以用 setsockopt 将其设置为 1 来禁用,然后再用 getsockopt 查看值的变化。
示例 2:获取套接字错误状态
SO_ERROR 是一个非常实用的选项,它允许你获取套接字上挂起的错误,这对于 connect() 或 accept() 操作后检查底层错误非常有用,因为它们本身可能不会返回详细的错误码。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
int main() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// 假设我们进行了一个失败的 connect 操作
struct sockaddr_in serv_addr;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(12345); // 一个很可能没人监听的端口
inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);
// connect 会失败,但 errno 会被设置
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
// perror("connect"); // 我们不在这里打印,而是用 getsockopt 检查
}
int error_code = 0;
socklen_t error_len = sizeof(error_code);
// 获取套接字的错误状态
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error_code, &error_len) < 0) {
perror("getsockopt SO_ERROR");
close(sockfd);
exit(EXIT_FAILURE);
}
if (error_code != 0) {
// 使用 strerror 将错误码转换为可读的字符串
printf("Socket has pending error: %s\n", strerror(error_code));
} else {
printf("No pending error on the socket.\n");
}
close(sockfd);
return 0;
}
编译和运行:
gcc getsockopt_example2.c -o getsockopt_example2 ./getsockopt_example2
可能输出:
Socket has pending error: Connection refused
这清晰地告诉我们 connect 失败的原因是“连接被拒绝”,而不是一个模糊的 "Operation failed"。
常用选项速查表
| Level | optname |
类型 | 描述 |
|---|---|---|---|
SOL_SOCKET |
SO_REUSEADDR |
int |
允许 bind() 重用处于 TIME_WAIT 状态的地址,常用于服务器重启。 |
SOL_SOCKET |
SO_KEEPALIVE |
int |
启用 TCP 保活机制,如果连接在一段时间内没有数据传输,TCP 会发送探测包来检查连接是否还活着。 |
SOL_SOCKET |
SO_RCVBUF |
int |
TCP 接收缓冲区的大小(字节)。 |
SOL_SOCKET |
SO_SNDBUF |
int |
TCP 发送缓冲区的大小(字节)。 |
SOL_SOCKET |
SO_TYPE |
int |
获取套接字的类型(SOCK_STREAM, SOCK_DGRAM)。 |
SOL_SOCKET |
SO_ERROR |
int |
获取并清除套接字上的挂起错误。 |
IPPROTO_TCP |
TCP_NODELAY |
int |
禁用 Nagle 算法。1 为禁用,0 为启用。 |
IPPROTO_TCP |
TCP_KEEPIDLE |
int |
在开始发送保活探测包之前,连接必须空闲的秒数。 |
IPPROTO_TCP |
TCP_KEEPINTVL |
int |
保活探测包之间的间隔秒数。 |
getsockopt 是 C 语言网络编程中一个不可或缺的工具,它让你能够:
- 查询配置:了解当前套接字是如何被配置的。
- 调试问题:通过
SO_ERROR等选项获取底层的、详细的错误信息。 - 动态调整:通过结合
getsockopt和setsockopt,可以根据程序运行时的状态动态地优化套接字性能。
记住它的核心用法:提供一个套接字描述符、一个协议层、一个选项名,以及一个用来存放结果的缓冲区和它的长度,理解了这五个参数,你就能掌握 getsockopt 的精髓。
