linux下getsockopt和setsockopt详解及测试

Posted singularity

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux下getsockopt和setsockopt详解及测试相关的知识,希望对你有一定的参考价值。

linux下getsockopt和setsockopt详解及测试

NAME

名字

       getsockopt, setsockopt - get and set options on sockets

       获取或者设置套接字的选项

SYNOPSIS

 函数原型

#include <sys/types.h>          /* See NOTES */
       #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);

参数:  

sock:将要被设置或者获取选项的套接字。
level:选项所在的协议层。
optname:需要访问的选项名。


optval:对于getsockopt(),指向返回选项值的缓冲。

             对于setsockopt(),指向包含新选项值的缓冲。


optlen:对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度。

              对于setsockopt(),The size, in bytes, of the optval buffer. 

level指定控制套接字的层次.可以取三种值:
     1)SOL_SOCKET:通用套接字选项.
     2)IPPROTO_IP:IP选项.
     3)IPPROTO_TCP:TCP选项.

RETURN VALUE

返回值

       On success, zero is returned.  On error, -1 is returned, and errno is set appropriately.

错误返回

ERRORS
	EBADF     The argument sockfd is not a valid descriptor.

	EFAULT    The  address  pointed  to  by optval is not in a valid part of the process address space.  For getsockopt(), this error may
		   also be returned if optlen is not in a valid part of the process address space.//

	EINVAL    optlen invalid in setsockopt().  In some cases this error can also occur for an invalid value  in  optval  (e.g.,  for  the
		   IP_ADD_MEMBERSHIP option described in ip(7)).

	ENOPROTOOPT
		   The option is unknown at the level indicated.

	ENOTSOCK  The argument sockfd is a file, not a socket.


EBADF:sock不是有效的文件描述词
EFAULT:optval指向的内存并非有效的进程空间
EINVAL:在调用setsockopt()时,optlen无效
ENOPROTOOPT:指定的协议层不能识别选项
ENOTSOCK:sock描述的不是套接字

套接字选项和IP层的套接字选项汇总见《unix网络编程第三版卷一》P151图7-1

下面用一段小代码来检查选项是否受支持并获取默认值:

[email protected]:/myworkspace/unixnetwork/unpv13e/sockopt# cat -n checkopts.c 
	1	/* include checkopts1 */
	2	/* *INDENT-OFF* */
	3	#include	"unp.h"
	4	#include	<netinet/tcp.h>		/* for TCP_xxx defines */
	5	
	6	union val {
	7	  int				i_val;
	8	  long				l_val;
	9	  struct linger		linger_val;
    10	  struct timeval	timeval_val;
    11	} val;
    12	
    13	static char	*sock_str_flag(union val *, int);
    14	static char	*sock_str_int(union val *, int);
    15	static char	*sock_str_linger(union val *, int);
    16	static char	*sock_str_timeval(union val *, int);
    17	
    18	struct sock_opts {
    19	  const char	   *opt_str;
    20	  int		opt_level;
    21	  int		opt_name;
    22	  char   *(*opt_val_str)(union val *, int);
    23	} sock_opts[] = {
    24		{ "SO_BROADCAST",		SOL_SOCKET,	SO_BROADCAST,	sock_str_flag },
    25		{ "SO_DEBUG",			SOL_SOCKET,	SO_DEBUG,		sock_str_flag },
    26		{ "SO_DONTROUTE",		SOL_SOCKET,	SO_DONTROUTE,	sock_str_flag },
    27		{ "SO_ERROR",			SOL_SOCKET,	SO_ERROR,		sock_str_int },
    28		{ "SO_KEEPALIVE",		SOL_SOCKET,	SO_KEEPALIVE,	sock_str_flag },
    29		{ "SO_LINGER",			SOL_SOCKET,	SO_LINGER,		sock_str_linger },
    30		{ "SO_OOBINLINE",		SOL_SOCKET,	SO_OOBINLINE,	sock_str_flag },
    31		{ "SO_RCVBUF",			SOL_SOCKET,	SO_RCVBUF,		sock_str_int },
    32		{ "SO_SNDBUF",			SOL_SOCKET,	SO_SNDBUF,		sock_str_int },
    33		{ "SO_RCVLOWAT",		SOL_SOCKET,	SO_RCVLOWAT,	sock_str_int },
    34		{ "SO_SNDLOWAT",		SOL_SOCKET,	SO_SNDLOWAT,	sock_str_int },
    35		{ "SO_RCVTIMEO",		SOL_SOCKET,	SO_RCVTIMEO,	sock_str_timeval },
    36		{ "SO_SNDTIMEO",		SOL_SOCKET,	SO_SNDTIMEO,	sock_str_timeval },
    37		{ "SO_REUSEADDR",		SOL_SOCKET,	SO_REUSEADDR,	sock_str_flag },
    38	#ifdef	SO_REUSEPORT
    39		{ "SO_REUSEPORT",		SOL_SOCKET,	SO_REUSEPORT,	sock_str_flag },
    40	#else
    41		{ "SO_REUSEPORT",		0,			0,				NULL },
    42	#endif
    43		{ "SO_TYPE",			SOL_SOCKET,	SO_TYPE,		sock_str_int },
    44	//	{ "SO_USELOOPBACK",		SOL_SOCKET,	SO_USELOOPBACK,	sock_str_flag },
    45		{ "IP_TOS",				IPPROTO_IP,	IP_TOS,			sock_str_int },
    46		{ "IP_TTL",				IPPROTO_IP,	IP_TTL,			sock_str_int },
    47	#ifdef	IPV6_DONTFRAG
    48		{ "IPV6_DONTFRAG",		IPPROTO_IPV6,IPV6_DONTFRAG,	sock_str_flag },
    49	#else
    50		{ "IPV6_DONTFRAG",		0,			0,				NULL },
    51	#endif
    52	#ifdef	IPV6_UNICAST_HOPS
    53		{ "IPV6_UNICAST_HOPS",	IPPROTO_IPV6,IPV6_UNICAST_HOPS,sock_str_int },
    54	#else
    55		{ "IPV6_UNICAST_HOPS",	0,			0,				NULL },
    56	#endif
    57	#ifdef	IPV6_V6ONLY
    58		{ "IPV6_V6ONLY",		IPPROTO_IPV6,IPV6_V6ONLY,	sock_str_flag },
    59	#else
    60		{ "IPV6_V6ONLY",		0,			0,				NULL },
    61	#endif
    62		{ "TCP_MAXSEG",			IPPROTO_TCP,TCP_MAXSEG,		sock_str_int },
    63		{ "TCP_NODELAY",		IPPROTO_TCP,TCP_NODELAY,	sock_str_flag },
    64	#ifdef	SCTP_AUTOCLOSE
    65		{ "SCTP_AUTOCLOSE",		IPPROTO_SCTP,SCTP_AUTOCLOSE,sock_str_int },
    66	#else
    67		{ "SCTP_AUTOCLOSE",		0,			0,				NULL },
    68	#endif
    69	#ifdef	SCTP_MAXBURST
    70		{ "SCTP_MAXBURST",		IPPROTO_SCTP,SCTP_MAXBURST,	sock_str_int },
    71	#else
    72		{ "SCTP_MAXBURST",		0,			0,				NULL },
    73	#endif
    74	#ifdef	SCTP_MAXSEG
    75		{ "SCTP_MAXSEG",		IPPROTO_SCTP,SCTP_MAXSEG,	sock_str_int },
    76	#else
    77		{ "SCTP_MAXSEG",		0,			0,				NULL },
    78	#endif
    79	#ifdef	SCTP_NODELAY
    80		{ "SCTP_NODELAY",		IPPROTO_SCTP,SCTP_NODELAY,	sock_str_flag },
    81	#else
    82		{ "SCTP_NODELAY",		0,			0,				NULL },
    83	#endif
    84		{ NULL,					0,			0,				NULL }
    85	};
    86	/* *INDENT-ON* */
    87	/* end checkopts1 */
    88	
    89	/* include checkopts2 */
    90	int
    91	main(int argc, char **argv)
    92	{
    93		int					fd;
    94		socklen_t			len;
    95		struct sock_opts	*ptr;
    96	
    97		for (ptr = sock_opts; ptr->opt_str != NULL; ptr++) {
    98			printf("%s: ", ptr->opt_str);
    99			if (ptr->opt_val_str == NULL)
   100				printf("(undefined)\n");
   101			else {
   102				switch(ptr->opt_level) {
   103				case SOL_SOCKET:
   104				case IPPROTO_IP:
   105				case IPPROTO_TCP:
   106					fd = Socket(AF_INET, SOCK_STREAM, 0);
   107					break;
   108	#ifdef	IPV6
   109				case IPPROTO_IPV6:
   110					fd = Socket(AF_INET6, SOCK_STREAM, 0);
   111					break;
   112	#endif
   113	#ifdef	IPPROTO_SCTP
   114				case IPPROTO_SCTP:
   115					fd = Socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
   116					break;
   117	#endif
   118				default:
   119					err_quit("Can‘t create fd for level %d\n", ptr->opt_level);
   120				}
   121	
   122				len = sizeof(val);
   123				if (getsockopt(fd, ptr->opt_level, ptr->opt_name,
   124							   &val, &len) == -1) {
   125					err_ret("getsockopt error");
   126				} else {
   127					printf("default = %s\n", (*ptr->opt_val_str)(&val, len));
   128				}
   129				close(fd);
   130			}
   131		}
   132		exit(0);
   133	}
   134	/* end checkopts2 */
   135	
   136	/* include checkopts3 */
   137	static char	strres[128];
   138	
   139	static char	*
   140	sock_str_flag(union val *ptr, int len)
   141	{
   142	/* *INDENT-OFF* */
   143		if (len != sizeof(int))
   144			snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
   145		else
   146			snprintf(strres, sizeof(strres),
   147					 "%s", (ptr->i_val == 0) ? "off" : "on");
   148		return(strres);
   149	/* *INDENT-ON* */
   150	}
   151	/* end checkopts3 */
   152	
   153	static char	*
   154	sock_str_int(union val *ptr, int len)
   155	{
   156		if (len != sizeof(int))
   157			snprintf(strres, sizeof(strres), "size (%d) not sizeof(int)", len);
   158		else
   159			snprintf(strres, sizeof(strres), "%d", ptr->i_val);
   160		return(strres);
   161	}
   162	
   163	static char	*
   164	sock_str_linger(union val *ptr, int len)
   165	{
   166		struct linger	*lptr = &ptr->linger_val;
   167	
   168		if (len != sizeof(struct linger))
   169			snprintf(strres, sizeof(strres),
   170					 "size (%d) not sizeof(struct linger)", len);
   171		else
   172			snprintf(strres, sizeof(strres), "l_onoff = %d, l_linger = %d",
   173					 lptr->l_onoff, lptr->l_linger);
   174		return(strres);
   175	}
   176	
   177	static char	*
   178	sock_str_timeval(union val *ptr, int len)
   179	{
   180		struct timeval	*tvptr = &ptr->timeval_val;
   181	
   182		if (len != sizeof(struct timeval))
   183			snprintf(strres, sizeof(strres),
   184					 "size (%d) not sizeof(struct timeval)", len);
   185		else
   186			snprintf(strres, sizeof(strres), "%d sec, %d usec",
   187					 tvptr->tv_sec, tvptr->tv_usec);
   188		return(strres);
   189	}
[email protected]:/myworkspace/unixnetwork/unpv13e/sockopt# man getsockopt

测试运行结果如图:

技术分享













以上是关于linux下getsockopt和setsockopt详解及测试的主要内容,如果未能解决你的问题,请参考以下文章

做一组后getsockopt SO_RECVBUF在linux中显示两倍的值?

getsockopt(...,SO_ORIGINAL_DST,...) 偶尔返回客户端地址

Linux socket编程 套接字选项

如何用getsockopt知道“序列号”?

为啥getsockopt optlen 为零?

setsockopt()和getsockopt()函数参数