Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1798045
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: 系统运维

2012-04-03 09:57:02

套接字机制为我们提供两个套接字选项接口来控制套接字的行为。一个接口用来设置选项,而另一 个接口允许我们查询一个选项的状态。我们可以得到并设置三种选项:


1、普通选项,和所有套接字一起工作。


2、在套接字级被管理的,但取决于底下的协议的支持选项。


3、协议指定选项,每个协议个体只有唯一一个。


SUS只定义了套接字级的选项(上述列表里的前两个选项类型)。


我们可以用setsockopt函数设置一个套接字选项。



  1. #include <sys/socket.h>

  2. int setsockopt(int sockfd, int level, int option, const void *val, socklen_t len);

  3. 成功返回0,错误返回-1。


level 参数标识选项要应用到的协议。如果选项是一个通用套接字级的选项,那么level被设置为SOL_SOCKET,否则,level被设置为控制这个选项的 协议号。例子有TCP选项的IPPROTO_TCP和IP选项的IPPROTO_IP。下表总结了由SUS定义的通用的套接字级的选项。


套接字选项
选项val参数类型描述
SO_ACCEPTCONNint返回一个套接字是否为监听开启(只应用于getsockopt)
SO_BROADCASTint如果*val非0,则广播数据报
SO_DEBUGint如果*val非0,则开启网络驱动的调试
SO_DONTROUTEint如果*val非0,则绕过通常的路由
SO_ERRORint返回并清理待定的套接字错误(只应用于getsockopt)
SO_KEEPALIVEint如果*val非0,则开启定期的keep-alive消息
SO_LINGERstruct linger当存在未发送的消息且套接字被关闭时的延迟时间
SO_OOBINLINEint如果*val非0,不同频道的数据被内嵌到普通数据里
SO_RCVBUFint接收缓冲的字节尺寸。
SO_RCVLOWATint当一个接收调用上要返回的数据的最少的量。
SO_RCVTIMEOstruct timeval一个套接字接收调用的计时值
SO_REUSEADDRint如果*val非0,则重用bind里的地址
SO_SNDBUFint发送缓冲的字节尺寸
SO_SNDLOWATint在一个发送调用里要传送的数据的最少的量。
SO_SNDTIMEOstruct timeval一个套接字发送调用的计时值
SO_TYPEint标识套接字类型(只适用于getsockopt)


val参数指向一个数据结构或一个整型,取决于选项。一些选项是开关。如果整型非0,那么选项被开启。如果整型为0,则选项被禁用。len参数指定val指向的对象的尺寸。


我们可以用getsockopt函数找到当前一个选项的值。



  1. #include <sys/socket.h>

  2. int getsockopt(int sockfd, int level, int option, void *restrict val, socklen_t *restrict lenp);

  3. 成功返回0,错误返回-1。


注意lenp参数是一个整型指针。在调用getsockopt前,我们设置这个整型为选项要拷贝到的缓冲的尺寸。如果选项的真实尺寸比这个尺寸大,那么选项被静默地裁切。如果选项的真实尺寸比这个尺寸小,那么在返回时这个整型被更新为真实的尺寸。


16.4节的initserver函数在服务器终止而我们尝试立即重启它时不能恰当地操作。通常,TCP的实现阻止我们绑定到相同的地址,直到计时到时,它通常大概是几分钟。幸运地,SO_REUSEADDR套接字选项允许我们绕过这个限制,如下面的代码所演示的。



  1. #include <errno.h>
  2. #include <sys/socket.h>

  3. int
  4. initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
  5. {
  6.     int fd, err;
  7.     int reuse = 1;

  8.     if ((fd = socket(addr->sa_family, type, 0)) < 0)
  9.         return(-1);
  10.     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
  11.         err = errno;
  12.         goto errout;
  13.     }
  14.     if (bind(fd, addr, alen) < 0) {
  15.         err = errno;
  16.         goto errout;
  17.     }
  18.     if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
  19.         if (listen(fd, qlen) < 0) {
  20.             err = errno;
  21.             goto errout;
  22.         }
  23.     }
  24.     return(fd);

  25. errout:
  26.     close(fd);
  27.     errno = err;
  28.     return(-1);
  29. }

为了开启SO_REUSEADDR选项,我们设置一个整型为非0值并传递这个整型的地址作为setsockopt的val参数。我们设置len参数为一个指定val所指的对象的尺寸的整型。
阅读(924) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~