0


【Linux C | 网络编程】套接字选项、getsockopt、setsockopt详解及C语言例子

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
⏰发布时间⏰:2024-02-27 09:02:30

本文未经允许,不得转发!!!

目录


在这里插入图片描述

🎄一、概述

在网络编程中,套接字选项经常需要用到,例如设置套接字缓冲区大小、设置套接字非阻塞等。在Linux中,与套接字选项相关的几个系统调用函数有:

getsockopt

setsockopt

fcntl

ioctl

。其中,

getsockopt

setsockopt

函数只能用于套接字选项,也是本文要求重点掌握的两个函数,而fcntl在网络编程中,最常见的就是将套接字设置成非阻塞。


在这里插入图片描述

🎄二、Linux系统下套接字选项

下面两个图片是Linux系统下套接字选项汇总,级别分别有:

SOL_SOCKET、IPPROTO_IP、IPPROTO_ICMPV6、IPPROTO_IPV6、IPPROTO_TCP、IPPROTO_SCTP

;数据类型中,用

{}

来表示结构体,如:

linger{}

表示

struct linger

timeval{}

表示

struct timeval

timeval{}

表示

struct timeval

1、套接字层和IP层的套接字选项汇总(见下图)
在这里插入图片描述

2、传输层的套接字选项汇总(见下图)
在这里插入图片描述


在这里插入图片描述

🎄三、getsockopt、setsockopt 函数

✨3.1 getsockopt、setsockopt 函数介绍

函数原型:

#include<sys/socket.h>intgetsockopt(int sockfd,int level,int optname,void*optval,socklen_t*optlen);intsetsockopt(int sockfd,int level,int optname,constvoid*optval,socklen_t optlen);
  • 函数说明:getsockoptsetstockopt用于获取或设置文件描述符sockfd引用的套接字的选项。
  • 函数参数: - sockfd:要操作的文件描述符sockfd;- level:级别,取值一般有:SOL_SOCKET、IPPROTO_IP、IPPROTO_ICMPV6、IPPROTO_IPV6、IPPROTO_TCP、IPPROTO_SCTP;- optname:选项名;- optval:指向某个变量的指针,用来存放获取或设置的值;- optlen:指明 optval 参数指向的内存大小。
  • 返回值:成功返回 0 ,出错返回 -1。

✨3.2 getsockopt、setsockopt 函数举例

下面代码是《unix网络编程卷1》源码进行修改的,可以依次打印获取到的套接字选项默认值。

// sockopt.c 修改自 《unix网络编程卷1》源码/* include checkopts1 *//* *INDENT-OFF* */#include<stdio.h>#include<sys/socket.h>#include<netinet/tcp.h>/* for TCP_xxx defines */union val {int                i_val;long                l_val;structlinger        linger_val;structtimeval    timeval_val;} val;staticchar*sock_str_flag(union val *,int);staticchar*sock_str_int(union val *,int);staticchar*sock_str_linger(union val *,int);staticchar*sock_str_timeval(union val *,int);structsock_opts{constchar*opt_str;int        opt_level;int        opt_name;char*(*opt_val_str)(union val *,int);} 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 },#ifdefSO_REUSEPORT{"SO_REUSEPORT",        SOL_SOCKET,    SO_REUSEPORT,    sock_str_flag },#else{"SO_REUSEPORT",0,0,NULL},#endif{"SO_TYPE",            SOL_SOCKET,    SO_TYPE,        sock_str_int },//    { "SO_USELOOPBACK",        SOL_SOCKET,    SO_USELOOPBACK,    sock_str_flag },//    { "IP_TOS",                IPPROTO_IP,    IP_TOS,            sock_str_int },//    { "IP_TTL",                IPPROTO_IP,    IP_TTL,            sock_str_int },#ifdefIPV6_DONTFRAG{"IPV6_DONTFRAG",        IPPROTO_IPV6,IPV6_DONTFRAG,    sock_str_flag },#else{"IPV6_DONTFRAG",0,0,NULL},#endif#ifdefIPV6_UNICAST_HOPS{"IPV6_UNICAST_HOPS",    IPPROTO_IPV6,IPV6_UNICAST_HOPS,sock_str_int },#else{"IPV6_UNICAST_HOPS",0,0,NULL},#endif#ifdefIPV6_V6ONLY{"IPV6_V6ONLY",        IPPROTO_IPV6,IPV6_V6ONLY,    sock_str_flag },#else{"IPV6_V6ONLY",0,0,NULL},#endif//    { "TCP_MAXSEG",            IPPROTO_TCP,TCP_MAXSEG,        sock_str_int },//    { "TCP_NODELAY",        IPPROTO_TCP,TCP_NODELAY,    sock_str_flag },#ifdefSCTP_AUTOCLOSE{"SCTP_AUTOCLOSE",        IPPROTO_SCTP,SCTP_AUTOCLOSE,sock_str_int },#else{"SCTP_AUTOCLOSE",0,0,NULL},#endif#ifdefSCTP_MAXBURST{"SCTP_MAXBURST",        IPPROTO_SCTP,SCTP_MAXBURST,    sock_str_int },#else{"SCTP_MAXBURST",0,0,NULL},#endif#ifdefSCTP_MAXSEG{"SCTP_MAXSEG",        IPPROTO_SCTP,SCTP_MAXSEG,    sock_str_int },#else{"SCTP_MAXSEG",0,0,NULL},#endif#ifdefSCTP_NODELAY{"SCTP_NODELAY",        IPPROTO_SCTP,SCTP_NODELAY,    sock_str_flag },#else{"SCTP_NODELAY",0,0,NULL},#endif{NULL,0,0,NULL}};/* *INDENT-ON* *//* end checkopts1 *//* include checkopts2 */intmain(int argc,char**argv){int                    fd;socklen_t            len;structsock_opts*ptr;for(ptr = sock_opts; ptr->opt_str !=NULL; ptr++){printf("%s: ", ptr->opt_str);if(ptr->opt_val_str ==NULL)printf("(undefined)\n");else{switch(ptr->opt_level){case SOL_SOCKET://            case IPPROTO_IP://            case IPPROTO_TCP:
                fd =socket(AF_INET, SOCK_STREAM,0);break;#ifdefIPV6case IPPROTO_IPV6:
                fd =socket(AF_INET6, SOCK_STREAM,0);break;#endif#ifdefIPPROTO_SCTPcase IPPROTO_SCTP:
                fd =socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);break;#endifdefault:printf("Can't create fd for level %d\n", ptr->opt_level);}

            len =sizeof(val);if(getsockopt(fd, ptr->opt_level, ptr->opt_name,&val,&len)==-1){printf("getsockopt error");}else{printf("default = %s\n",(*ptr->opt_val_str)(&val, len));}close(fd);}}return0;}/* end checkopts2 *//* include checkopts3 */staticchar    strres[128];staticchar*sock_str_flag(union val *ptr,int len){/* *INDENT-OFF* */if(len !=sizeof(int))snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)", len);elsesnprintf(strres,sizeof(strres),"%s",(ptr->i_val ==0)?"off":"on");return(strres);/* *INDENT-ON* */}/* end checkopts3 */staticchar*sock_str_int(union val *ptr,int len){if(len !=sizeof(int))snprintf(strres,sizeof(strres),"size (%d) not sizeof(int)", len);elsesnprintf(strres,sizeof(strres),"%d", ptr->i_val);return(strres);}staticchar*sock_str_linger(union val *ptr,int len){structlinger*lptr =&ptr->linger_val;if(len !=sizeof(structlinger))snprintf(strres,sizeof(strres),"size (%d) not sizeof(struct linger)", len);elsesnprintf(strres,sizeof(strres),"l_onoff = %d, l_linger = %d",
                 lptr->l_onoff, lptr->l_linger);return(strres);}staticchar*sock_str_timeval(union val *ptr,int len){structtimeval*tvptr =&ptr->timeval_val;if(len !=sizeof(structtimeval))snprintf(strres,sizeof(strres),"size (%d) not sizeof(struct timeval)", len);elsesnprintf(strres,sizeof(strres),"%ld sec, %ld usec",
                 tvptr->tv_sec, tvptr->tv_usec);return(strres);}

运行结果:
在这里插入图片描述

在这里插入图片描述

🎄四、常见的通用套接字选项

  • SO_BROADCAST:开启或禁止进程发送广播消息的能力。只有数据报套接字支持广播;
  • SO_KEEPALIVE:给一个TCP套接字设置保持存活(keep-alive)选项后,如果2小时内在该套接字的任一方向上都没有数据交换,TCP就自动给对端发送一个保持存活探测分节(keep-alive probe)。
  • SO_LINGER:本选项指定close函数对面向连接的协议(例如TCP和SCTP,但不是UDP)如何操作。默认操作是close立即返回,但是如果有数据残留在套接字发送缓冲区中,系统将试着把这些数据发送给对端。
  • SO_RCVBUF:获取或设置接收缓冲区大小。接收缓冲区被TCP、UDP和SCTP用来保存接收到的数据,直到由应用进程来读取;
  • SO_SNDBUF:获取或设置发送缓冲区大小。
  • SO_RCVLOWAT:接收低水位标记。让select函数返回“可读”时套接字接收缓冲区中所需的数据量。
  • SO_SNDLOWAT:发送低水位标记。让select函数返回“可写”时套接字发送缓冲区中所需的可用空间。
  • SO_REUSEADDR: (1) SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作它们的本地端口的连接仍存在。 (2) SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。 (3) SO_REUSEADDR允许单个进程捆绑同一端口到多个套接字上,只要每次捆绑指定不同的本地P地址即可。 (4) SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口已绑定到某个套接字上时,如果传输协议支持,同样的IP地址和端口还可以捆绑到另一个套接字上。一般来说本特性仅支持UDP套接字。

在这里插入图片描述

🎄五、总结

👉本文介绍网络编程中的套接字选项,先是汇总了常见的套接字选项,然后介绍获取和设置套接字选项的函数getsockopt、setsockopt,并给出对应的C语言例子,最后列出几个常见的通用套接字选项。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

标签: linux c语言 网络

本文转载自: https://blog.csdn.net/wkd_007/article/details/136074988
版权归原作者 wkd_007 所有, 如有侵权,请联系我们删除。

“【Linux C | 网络编程】套接字选项、getsockopt、setsockopt详解及C语言例子”的评论:

还没有评论