getsockopt
, setsockopt
: get or set options on sockets.
获取或者设置套接字的选项
#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sockfd:将要被设置或者获取选项的套接字。
level:选项所在的协议层。SOL_SOCKET
, IPPROTO_IP
, IPPROTO_TCP
optname:需要访问的选项名。
optval:对于getsockopt(),指向返回选项值的缓冲。对于setsockopt(),指向包含新选项值的缓冲。
optlen:optval缓冲区的长度。
成功执行时,返回0
。失败返回-1,errno被设为以下的某个值
EBADF:sockfd不是有效的文件描述词
EFAULT:optval指向的内存并非有效的进程空间
EINVAL:在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sockfd描述的不是套接字
level 为 SOL_SOCKET
optname | desc | type |
---|---|---|
SO_BROADCAST | 允许发送广播数据 | int |
SO_DEBUG | 允许调试 | int |
SO_DONTROUTE | 不查找路由 | int |
SO_ERROR | 获得套接字错误 | int |
SO_KEEPALIVE |
保持连接 | int |
SO_LINGER | 延迟关闭连接 | struct linger |
SO_OOBINLINE | 带外数据放入正常数据流 | int |
SO_RCVBUF | 接收缓冲区大小 | int |
SO_SNDBUF | 发送缓冲区大小 | int |
SO_RCVLOWAT | 接收缓冲区下限 | int |
SO_SNDLOWAT | 发送缓冲区下限 | int |
SO_RCVTIMEO | 接收超时 | struct timeval |
SO_SNDTIMEO | 发送超时 | struct timeval |
SO_REUSERADDR |
允许重用本地地址和端口 | int |
SO_TYPE | 获得套接字类型 | int |
SO_BSDCOMPAT | 与BSD系统兼容 | int |
level 为 IPPROTO_IP
optname | desc | type |
---|---|---|
IP_HDRINCL | 在数据包中包含IP首部 | int |
IP_TOS | 服务类型 | |
IP_TTL | 生存时间 | int |
level 为 IPPRO_TCP
optname | desc | type |
---|---|---|
TCP_MAXSEG | TCP最大数据段的大小 | int |
TCP_NODELAY |
不使用Nagle算法 | int |
常见用法
//设置socket可重用
int reuse = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, sizeof(int));
//设置socket保持连接状态
int keepalive = 1;
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive));
使用 getsockopt() 检测当前所有参数默认值状态
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <stdio.h>
union val {
int i_val;
long l_val;
struct linger linger_val;
struct timeval timeval_val;
}val;
static char *sock_str_flag(union val *, int);
static char *sock_str_int(union val *, int);
static char *sock_str_linger(union val *, int);
static char *sock_str_timeval(union val *, int);
struct sock_opts {
const char* opt_str;
int opt_level;
int opt_name;
char* (*opt_val_str)(union val *, int);
};
struct sock_opts G_sock_opts[] = {
{ "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, sock_str_flag },
{ "SO_DEBUG", SOL_SOCKET, SO_DEBUG, sock_str_flag },
{ "SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE, sock_str_flag },
{ "SO_ERROR", SOL_SOCKET, SO_ERROR, sock_str_int },
{ "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, sock_str_flag },
{ "SO_LINGER", SOL_SOCKET, SO_LINGER, sock_str_linger },
{ "SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE, sock_str_flag },
{ "SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, sock_str_int },
{ "SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, sock_str_int },
{ "SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, sock_str_int },
{ "SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, sock_str_int },
{ "SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, sock_str_timeval },
{ "SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, sock_str_timeval },
{ "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, sock_str_flag },
{ "SO_TYPE", SOL_SOCKET, SO_TYPE, sock_str_int },
{ "SO_BSDCOMPAT", SOL_SOCKET, SO_BSDCOMPAT, sock_str_int },
{ "IP_HDRINCL", IPPROTO_IP, IP_HDRINCL, sock_str_int },
{ "IP_TOS", IPPROTO_IP, IP_TOS, sock_str_int },
{ "IP_TTL", IPPROTO_IP, IP_TTL, sock_str_int },
{ "TCP_MAXSEG", IPPROTO_TCP,TCP_MAXSEG, sock_str_int },
{ "TCP_NODELAY", IPPROTO_TCP,TCP_NODELAY, sock_str_flag },
{ NULL, 0, 0, NULL }
};
static char strres[128];
static char *
sock_str_flag(union val *ptr, int len) {
if (len != sizeof(int)) {
snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
}
else {
snprintf(strres, sizeof(strres), "%s", (ptr->i_val == 0) ? "off" : "on");
}
return(strres);
}
static char *
sock_str_int(union val *ptr, int len) {
if (len != sizeof(int)) {
snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
}
else {
snprintf(strres, sizeof(strres), "%d", ptr->i_val);
}
return(strres);
}
static char *
sock_str_linger(union val *ptr, int len) {
struct linger* lptr = &ptr->linger_val;
if (len != sizeof(struct linger)) {
snprintf(strres, sizeof(strres), "size (%d) not sizeof(struct linger)", len);
}
else {
snprintf(strres, sizeof(strres), "l_onoff = %d, l_linger = %d", lptr->l_onoff, lptr->l_linger);
}
return(strres);
}
static char *
sock_str_timeval(union val *ptr, int len) {
struct timeval* tvptr = &ptr->timeval_val;
if (len != sizeof(struct timeval)) {
snprintf(strres, sizeof(strres),"size (%d) not sizeof(struct timeval)", len);
}
else {
snprintf(strres, sizeof(strres), "%ld sec, %ld usec",tvptr->tv_sec, tvptr->tv_usec);
}
return(strres);
}
int
main(int argc, char **argv) {
int fd;
socklen_t len;
struct sock_opts *ptr;
for (ptr = G_sock_opts; ptr->opt_str != NULL; ptr++) {
printf("%s: ", ptr->opt_str);
if (ptr->opt_val_str == NULL)
printf("(undefined)\n");
else {
fd = socket(AF_INET, SOCK_STREAM, 0);
len = sizeof(val);
if (getsockopt(fd, ptr->opt_level, ptr->opt_name, &val, &len) == -1) {
printf("get socket options err\n");
} else {
printf("default = %s\n", (*ptr->opt_val_str)(&val, len));
}
close(fd);
}
}
return 0;
}
输出:
SO_BROADCAST: default = off
SO_DEBUG: default = off
SO_DONTROUTE: default = off
SO_ERROR: default = 0
SO_KEEPALIVE: default = off
SO_LINGER: default = l_onoff = 0, l_linger = 0
SO_OOBINLINE: default = off
SO_RCVBUF: default = 87380
SO_SNDBUF: default = 16384
SO_RCVLOWAT: default = 1
SO_SNDLOWAT: default = 1
SO_RCVTIMEO: default = 0 sec, 0 usec
SO_SNDTIMEO: default = 0 sec, 0 usec
SO_REUSEADDR: default = off
SO_TYPE: default = 1
SO_BSDCOMPAT: default = 0
IP_HDRINCL: default = 0
IP_TOS: default = 0
IP_TTL: default = 64
TCP_MAXSEG: default = 536
TCP_NODELAY: default = off