五个网站页面,如何用域名建网站,网站建设与维护相关知识,html制作电影网站【 getsockopt/setsockopt系统调用功能描述#xff1a; 获取或者设置与某个套接字关联的选 项。选项可能存在于多层协议中#xff0c;它们总会出现在最上面的套接字层。当操作套接字选项时#xff0c;选项位于的层和选项的名称必须给出。为了操作套接字层的选项#xff0c;…【 getsockopt/setsockopt系统调用功能描述 获取或者设置与某个套接字关联的选 项。选项可能存在于多层协议中它们总会出现在最上面的套接字层。当操作套接字选项时选项位于的层和选项的名称必须给出。为了操作套接字层的选项应该 将层的值指定为SOL_SOCKET。为了操作其它层的选项控制选项的合适协议号必须给出。例如为了表示一个选项由TCP协议解析层应该设定为协议 号TCP。
用法 #include#include
int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
参数 sock将要被设置或者获取选项的套接字。level选项所在的协议层。optname需要访问的选项名。optval对于getsockopt()指向返回选项值的缓冲。对于setsockopt()指向包含新选项值的缓冲。optlen对于getsockopt()作为入口参数时选项值的最大长度。作为出口参数时选项值的实际长度。对于setsockopt()现选项的长度。 返回说明 成功执行时返回0。失败返回-1errno被设为以下的某个值 EBADFsock不是有效的文件描述词EFAULToptval指向的内存并非有效的进程空间EINVAL在调用setsockopt()时optlen无效ENOPROTOOPT指定的协议层不能识别选项ENOTSOCKsock描述的不是套接字
首先知道setsockopt()函数的KEEPALIVE属性是周期地测试连接是否仍存活 我上网查了很多资料还是不知道如何使用 最后硬着头皮自己写了一个服务器端和一个客户端的套接字连接 分别设置了两端的KEEPALIVE属性为打开 服务器端 #include #include #include #include #include #include #include #include #include #include #define SERVPORT 6000 //设定服务器服务端口为6000 #define MAX_LISTEN_SOCK_NUM 20 //设定可监听套接字的最大个数为20 int main() { //sockfd为本地监听套接字标识符client_fd为客户端套接字标识符 int sockfd,client_fd; struct sockaddr_in my_addr; struct sockaddr_in client_addr; //创建本地监听套接字 if((sockfdsocket(AF_INET,SOCK_STREAM,0))-1){ perror(套接字创建失败!/n); exit(1); } //设置套接字的属性使它能够在计算机重启的时候可以再次使用套接字的端口和IP int err,sock_reuse1; errsetsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)sock_reuse,sizeof(sock_reuse)); if(err!0){ printf(套接字可重用设置失败!/n); exit(1); } my_addr.sin_familyAF_INET; my_addr.sin_porthtons(SERVPORT); my_addr.sin_addr.s_addrINADDR_ANY; bzero((my_addr.sin_zero),8); //绑定套接字 if(bind(sockfd,(struct sockaddr *)my_addr,sizeof(struct sockaddr))-1){ perror(绑定失败!/n); exit(1); } //设置监听 if((listen(sockfd,MAX_LISTEN_SOCK_NUM))-1){ perror(设置监听失败!/n); exit(1); } printf(套接字进入监听状态等待请求连接/n); //int time_to_quit1; //while(time_to_quit){ //可以通过设置time_to_quit来主动关闭服务器端 while(1){ //有连接请求时进行连接 socklen_t sin_sizesizeof(struct sockaddr_in); if((client_fdaccept(sockfd,(struct sockaddr *)client_addr,sin_size))-1){ perror(接受连接失败!/n); continue; } int opt; socklen_t lensizeof(int); if((getsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char*)opt,len))0){ printf(SO_KEEPALIVE Value: %d/n, opt); } printf(接到一个来自%s的连接/n,inet_ntoa(client_addr.sin_addr)); //创建子进程来处理已连接的客户端套接字 if(send(client_fd,您好您已经连接成功!/n,50,0)-1){ perror(发送通知信息失败!/n); exit(0); } } close(client_fd); return 0; } 客户端 #include #include #include #include #include #include #include #include #include #include #define MAXDATASIZE 100 int main() { int sockfd,nbytes,serv_port; char buf_serv_ip[16],buf[26]; struct sockaddr_in serv_addr; if((sockfdsocket(AF_INET,SOCK_STREAM,0))-1){ perror(创建套接字失败!/n); exit(1); } //创建套接字成功后设置其可重用的属性 int KeepAlive1; socklen_t KPlensizeof(int); if(setsockopt(sockfd,SOL_SOCKET,SO_KEEPALIVE,(char *)KeepAlive,KPlen)!0){ perror(设置周期测试连接是否仍存活失败!/n); exit(1); } printf(请输入要连接主机的IP地址/n); scanf(%s,buf_serv_ip); printf(请输入要连接主机的端口号:/n); scanf(%d,serv_port); serv_addr.sin_familyAF_INET; serv_addr.sin_addr.s_addrinet_addr(buf_serv_ip); serv_addr.sin_porthtons(serv_port); bzero((serv_addr.sin_zero),8); if(connect(sockfd,(struct sockaddr *)serv_addr,sizeof(struct sockaddr))-1){ perror(连接服务器失败!/n); exit(1); } printf(连接服务器成功!/n); //在此处可以先接受判断将要接受数据的长度再创建数组 if((nbytesrecv(sockfd,buf,26,0))-1){ perror(接受数据失败!/n); exit(1); } buf[nbytes]/0; printf(接受的数据为:%s/n,buf); close(sockfd); return 0; } 分别在两个终端运在同一个主机上行先启动服务器端;再启动客户端,向服务器端请求连接连接成功后客户端套接字关闭服务器端套接字始终打开等待两个小时多也没有反应 肯请高手指点 1这样做能达到预期报告连接是否仍存在的效果吗 2不能的话应该如何做 3还有getsockopt()的相关功能又是什么哪在上面的程序中没有用到该函数 4看了unix网络编程上的一点关于该问题的解释还是不明白因为她提到要两个小时才回应但等了撒小时也没有反应她还说可以缩短时间我却不知道如何缩短
getsockopt和setsockopt 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) level指定控制套接字的层次.可以取三种值: 1)SOL_SOCKET:通用套接字选项. 2)IPPROTO_IP:IP选项. 3)IPPROTO_TCP:TCP选项. optname指定控制的方式(选项的名称),我们下面详细解释 optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换 选项名称 说明 数据类型 SOL_SOCKET ------------------------------------------------------------------------ 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 IPPROTO_IP ------------------------------------------------------------------------IP_HDRINCL 在数据包中包含IP首部 int IP_OPTINOS IP首部选项 int IP_TOS 服务类型 IP_TTL 生存时间 int IPPRO_TCP ------------------------------------------------------------------------TCP_MAXSEG TCP最大数据段的大小 int TCP_NODELAY 不使用Nagle算法 int 返回说明 成功执行时返回0。失败返回-1errno被设为以下的某个值 EBADFsock不是有效的文件描述词EFAULToptval指向的内存并非有效的进程空间EINVAL在调用setsockopt()时optlen无效ENOPROTOOPT指定的协议层不能识别选项ENOTSOCKsock描述的不是套接字 SO_RCVBUF和SO_SNDBUF每个套接口都有一个发送缓冲区和一个接收缓冲区使用这两个套接口选项可以改变缺省缓冲区大小。 // 接收缓冲区int nRecvBuf32*1024; //设置为32Ksetsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)nRecvBuf,sizeof(int)); //发送缓冲区int nSendBuf32*1024;//设置为32Ksetsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)nSendBuf,sizeof(int)); 注意 当设置TCP套接口接收缓冲区的大小时函数调用顺序是很重要的因为TCP的窗口规模选项是在建立连接时用SYN与对方互换得到的。对于客户SO_RCVBUF选项必须在connect之前设置对于服务器SO_RCVBUF选项必须在listen前设置。 如下内容转自http://linux.chinaunix.net/techdoc/net/2007/11/01/971094.shtml 有时候我们要控制套接字的行为(如修改缓冲区的大小),这个时候我们就要控制套接字的选项了. 以下资料均从网上收集得到 getsockopt 和 setsockopt 获得套接口选项 代码: int getsockopt ( int sockfd, int level, int optname, void * optval, socklen_t *opteln ) 设置套接口选项 int setsockopt ( int sockfd, int level, int optname, const void * optval, socklen_t *opteln ) sockfd(套接字): 指向一个打开的套接口描述字 level:(级别) 指定选项代码的类型。 SOL_SOCKET: 基本套接口 IPPROTO_IP: IPv4套接口 IPPROTO_IPV6: IPv6套接口 IPPROTO_TCP: TCP套接口 optname(选项名) 选项名称 optval(选项值): 是一个指向变量的指针 类型整形套接口结构 其他结构类型:linger{}, timeval{ } optlen(选项长度) optval 的大小 返回值标志打开或关闭某个特征的二进制选项 以下说明方法为 选项名称 简要说明 数据类型 补充 SOL_SOCKET ------------------------------------------------------------------------ SO_BROADCAST 允许发送广播数据 int 适用於 UDP socket。其意义是允许 UDP socket 「广播」broadcast讯息到网路上。 SO_DEBUG 允许调试 int SO_DONTROUTE 不查找路由 int SO_ERROR 获得套接字错误 int SO_KEEPALIVE 保持连接 int 检测对方主机是否崩溃避免服务器永远阻塞于TCP连接的输入。设置该选项后如果2小时内在此套接口的任一方向都没有数据交换TCP就自动给对方 发一个保持存活探测分节(keepaliveprobe)。这是一个对方必须响应的TCP分节.它会导致以下三种情况对方接收一切正常以期望的ACK响应。2小时后TCP将发出另一个探测分节。对方已崩溃且已重新启动以RST响应。套接口的待处理错误被置为ECONNRESET套接 口本身则被关闭。对方无任何响应源自berkeley的TCP发送另外8个探测分节相隔75秒一个试图得到一个响应。在发出第一个探测分节11分钟15秒后若仍无响应就放弃。套接口的待处理错误被置为ETIMEOUT套接口本身则被关闭。如ICMP错误是“host unreachable(主机不可达)”说明对方主机并没有崩溃但是不可达这种情况下待处理错误被置为 EHOSTUNREACH。 SO_DONTLINGER 若为真则SO_LINGER选项被禁止。 SO_LINGER 延迟关闭连接 struct linger 上面这两个选项影响close行为 选项 间隔 关闭方式 等待关闭与否 SO_DONTLINGER 不关心 优雅 否 SO_LINGER 零 强制 否 SO_LINGER 非零 优雅 是 若设置了SO_LINGER亦即linger结构中的l_onoff域设为非零参见2.44.1.7和4.1.21各节并设置了零超时间隔则closesocket()不被阻塞立即执行不论是否有排队数据未发送或未被确认。这种关闭方式称为“强制”或“失效”关闭因为套接口的虚电路立即被复位且丢失了未发送的数据。在远端的recv()调用将以WSAECONNRESET出错。 若设置了SO_LINGER并确定了非零的超时间隔则closesocket()调用阻塞进程直到所剩数据发送完毕或超时。这种关闭称为“优雅的”关闭。请注意如果套接口置为非阻塞且SO_LINGER设为非零超时则closesocket()调用将以WSAEWOULDBLOCK错误返回。 若在一个流类套接口上设置了SO_DONTLINGER也就是说将linger结构的l_onoff域设为零参见2.44.1.74.1.21节则closesocket()调用立即返回。但是如果可能排队的数据将在套接口关闭前发送。请注意在这种情况下WINDOWS套接口实现将在一段不确定的时间内保留套接口以及其他资源这对于想用所以套接口的应用程序来说有一定影响。 SO_OOBINLINE 带外数据放入正常数据流,在普通数据流中接收带外数据 int SO_RCVBUF 接收缓冲区大小 int 设置接收缓冲区的保留大小 与 SO_MAX_MSG_SIZE 或TCP滑动窗口无关如果一般发送的包很大很频繁那么使用这个选项 SO_SNDBUF 发送缓冲区大小 int 设置发送缓冲区的保留大小 与 SO_MAX_MSG_SIZE 或TCP滑动窗口无关如果一般发送的包很大很频繁那么使用这个选项 每个套接口都有一个发送缓冲区和一个接收缓冲区。 接收缓冲区被TCP和UDP用来将接收到的数据一直保存到由应用进程来读。TCPTCP通告另一端的窗口大小。 TCP套接口接收缓冲区不可能溢出因为对方不允许发出超过所通告窗口大小的数据。这就是TCP的流量控制如果对方无视窗口大小而发出了超过宙口大小的数据则接 收方TCP将丢弃它。UDP当接收到的数据报装不进套接口接收缓冲区时此数据报就被丢弃。UDP是没有流量控制的快的发送者可以很容易地就淹没慢的接收者导致接收方的UDP丢弃数据报。 SO_RCVLOWAT 接收缓冲区下限 int SO_SNDLOWAT 发送缓冲区下限 int 每个套接口都有一个接收低潮限度和一个发送低潮限度。它们是函数selectt使用的接收低潮限度是让select返回“可读”而在套接口接收缓冲区中必须有的数据总量。——对于一个TCP或UDP套接口此值缺省为1。发送低潮限度是让select返回“可写”而在套接口发送缓冲区中必须有的可用空间。对于TCP套接口此值常缺省为2048。 对于UDP使用低潮限度由于其发送缓冲区中可用空间的字节数是从不变化的只要 UDP套接口发送缓冲区大小大于套接口的低潮限度这样的UDP套接口就总是可写的。UDP没有发送缓冲区只有发送缓冲区的大小。 SO_RCVTIMEO 接收超时 struct timeval SO_SNDTIMEO 发送超时 struct timeval SO_REUSERADDR 允许重用本地地址和端口 int 充许绑定已被使用的地址或端口号可以参考bind的man SO_EXCLUSIVEADDRUSE 独占模式使用端口,就是不充许和其它程序使用SO_REUSEADDR共享的使用某一端口。 在确定多重绑定使用谁的时候根据一条原则是谁的指定最明确则将包递交给谁而且没有权限之分也就是说低级权限的用户是可以重绑定在高级权限如服务启动的端口上的,这是非常重大的一个安全隐患, 如果不想让自己程序被监听那么使用这个选项 SO_TYPE 获得套接字类型 int SO_BSDCOMPAT 与BSD系统兼容 int IPPROTO_IP -------------------------------------------------------------------------- IP_HDRINCL 在数据包中包含IP首部 int 这个选项常用于黑客技术中隐藏自己的IP地址 IP_OPTINOS IP首部选项 int IP_TOS 服务类型 IP_TTL 生存时间 int 以下IPV4选项用于组播 IPv4 选项 数据类型 描 述 IP_ADD_MEMBERSHIP struct ip_mreq 加入到组播组中 IP_ROP_MEMBERSHIP struct ip_mreq 从组播组中退出 IP_MULTICAST_IF struct ip_mreq 指定提交组播报文的接口 IP_MULTICAST_TTL u_char 指定提交组播报文的TTL IP_MULTICAST_LOOP u_char 使组播报文环路有效或无效 在头文件中定义了ip_mreq结构 代码: struct ip_mreq { struct in_addr imr_multiaddr; struct in_addr imr_interface; }; 若进程要加入到一个组播组中用soket的setsockopt()函数发送该选项。该选项类型是ip_mreq结构它的第一个字段imr_multiaddr指定了组播组的地址第二个字段imr_interface指定了接口的IPv4地址。 IP_DROP_MEMBERSHIP 该选项用来从某个组播组中退出。数据结构ip_mreq的使用方法与上面相同。 IP_MULTICAST_IF 该选项可以修改网络接口在结构ip_mreq中定义新的接口。 IP_MULTICAST_TTL 设置组播报文的数据包的TTL生存时间。默认值是1表示数据包只能在本地的子网中传送。 IP_MULTICAST_LOOP 组播组中的成员自己也会收到它向本组发送的报文。这个选项用于选择是否激活这种状态。IPPRO_TCP -------------------------------------------------------------------------- TCP_MAXSEG TCP最大数据段的大小 int 获取或设置TCP连接的最大分节大小(MSS)。返回值是我们的TCP发送给另一端的最大数据量它常常就是由另一端用SYN分节通告的MSS除非我们的TCP选择使用一个比对方通告的MSS小些的值。如果此值在套接口连接之前取得则返回值为未从另·—端收到Mss选项的情况下所用的缺省值。小于此返回值的信可能真正用在连接上因为譬如说使用时间戳选项的话它在每个分节上占用12字节的TCP选项容量。我们的TcP将发送的每个分节的最大数据量也可在连接存活期内改变但前提是TCP要支持路径MTU 发现功能。如果到对方的路径改变了此值可上下调整。 TCP_NODELAY 不使用Nagle算法 int 指定TCP开始发送保持存活探测分节前以秒为单位的连接空闲时间。缺省值至少必须为7200秒即2小时。此选项仅在SO_KEPALIVEE套接口选项打开时才有效。 TCP_NODELAY 和 TCP_CORK 这两个选项都对网络连接的行为具有重要的作用。许多UNIX系统都实现了TCP_NODELAY选项但是TCP_CORK则是Linux系统所独有的而且相对较新它首先在内核版本2.4上得以实现。此外其他UNIX系统版本也有功能类似的选项值得注意的是在某种由BSD派生的系统上的TCP_NOPUSH选项其实就是TCP_CORK的一部分具体实现。 TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”Nagle化在这里的含义是采用Nagle算法把较小的包组装为更大的帧。JohnNagle是Nagle算法的发明人后者就是用他的名字来命名的他在1984年首次用这种方法来尝试解决福特汽车公司的网络拥塞问题欲了解详情请参看IETF RFC 896。他解决的问题就是所谓的silly window syndrome中文称“愚蠢窗口症候群”具体含义是因为普遍终端应用程序每产生一次击键操作就会发送一个包而典型情况下一个包会拥有一个字节的数据载荷以及40个字节长的包头于是产生4000%的过载很轻易地就能令网络发生拥塞,。Nagle化后来成了一种标准并且立即在因特网上得以实现。它现在已经成为缺省配置了但在我们看来有些场合下把这一选项关掉也是合乎需要的。 现在让我们假设某个应用程序发出了一个请求希望发送小块数据。我们可以选择立即发送数据或者等待产生更多的数据然后再一次发送两种策略。如果我们马上发送数据那么交互性的以及客户/服务器型的应用程序将极大地受益。例如当我们正在发送一个较短的请求并且等候较大的响应时相关过载与传输的数据总量相比就会比较低而且如果请求立即发出那么响应时间也会快一些。以上操作可以通过设置套接字的TCP_NODELAY选项来完成这样就禁用了Nagle算法。 另外一种情况则需要我们等到数据量达到最大时才通过网络一次发送全部数据这种数据传输方式有益于大量数据的通信性能典型的应用就是文件服务器。应用Nagle算法在这种情况下就会产生问题。但是如果你正在发送大量数据你可以设置TCP_CORK选项禁用Nagle化其方式正好同TCP_NODELAY相反TCP_CORK 和 TCP_NODELAY 是互相排斥的。下面就让我们仔细分析下其工作原理。 假设应用程序使用sendfile()函数来转移大量数据。应用协议通常要求发送某些信息来预先解释数据这些信息其实就是报头内容。典型情况下报头很小而且套接字上设置了TCP_NODELAY。有报头的包将被立即传输在某些情况下取决于内部的包计数器因为这个包成功地被对方收到后需要请求对方确认。这样大量数据的传输就会被推迟而且产生了不必要的网络流量交换。 但是如果我们在套接字上设置了TCP_CORK可以比喻为在管道上插入“塞子”选项具有报头的包就会填补大量的数据所有的数据都根据大小自动地通过包传输出去。当数据传输完成时最好取消TCP_CORK选项设置给连接“拔去塞子”以便任一部分的帧都能发送出去。这同“塞住”网络连接同等重要。 总而言之如果你肯定能一起发送多个数据集合例如HTTP响应的头和正文那么我们建议你设置TCP_CORK选项这样在这些数据之间不存在延迟。能极大地有益于WWW、FTP以及文件服务器的性能同时也简化了你的工作。示例代码如下 intfd, on 1; … … setsockopt (fd, SOL_TCP, TCP_CORK, on, sizeof (on)); write (fd, …); fprintf (fd, …); sendfile (fd, …); write (fd, …); sendfile (fd, …); … on 0; setsockopt (fd, SOL_TCP, TCP_CORK, on, sizeof (on)); 不幸的是许多常用的程序并没有考虑到以上问题。例如Eric Allman编写的sendmail就没有对其套接字设置任何选项。 ApacheHTTPD是因特网上最流行的Web服务器它的所有套接字就都设置了TCP_NODELAY选项而且其性能也深受大多数用户的满意。这是为什么呢答案就在于实现的差别之上。由BSD衍生的TCP/IP协议栈值得注意的是FreeBSD在这种状况下的操作就不同。当在TCP_NODELAY模式下提交大量小数据块传输时大量信息将按照一次write()函数调用发送一块数据的方式发送出去。然而因为负责请求交付确认的记数器是面向字节而非面向包在Linux上的所以引入延迟的概率就降低了很多。结果仅仅和全部数据的大小有关系。而 Linux在第一包到达之后就要求确认FreeBSD则在进行如此操作之前会等待好几百个包。 在Linux系统上TCP_NODELAY的效果同习惯于BSD TCP/IP协议栈的开发者所期望的效果有很大不同而且在Linux上的Apache性能表现也会更差些。其他在Linux上频繁采用TCP_NODELAY的应用程序也有同样的问题。 TCP_DEFER_ACCEPT 我们首先考虑的第1个选项是TCP_DEFER_ACCEPT这是Linux系统上的叫法其他一些操作系统上也有同样的选项但使用不同的名字。为了理解TCP_DEFER_ACCEPT选项的具体思想我们有必要大致阐述一下典型的HTTP客户/服务器交互过程。请回想下TCP是如何与传输数据的目标建立连接的。在网络上在分离的单元之间传输的信息称为IP包或IP数据报。一个包总有一个携带服务信息的包头包头用于内部协议的处理并且它也可以携带数据负载。服务信息的典型例子就是一套所谓的标志它把包标记代表TCP/IP协议栈内的特殊含义例如收到包的成功确认等等。通常在经过“标记”的包里携带负载是完全可能的但有时内部逻辑迫使TCP/IP协议栈发出只有包头的IP包。这些包经常会引发讨厌的网络延迟而且还增加了系统的负载结果导致网络性能在整体上降低。 现在服务器创建了一个套接字同时等待连接。TCP/IP式的连接过程就是所谓“3次握手”。首先客户程序发送一个设置SYN标志而且不带数据负载的TCP包一个SYN包。服务器则以发出带SYN/ACK标志的数据包一个SYN/ACK包作为刚才收到包的确认响应。客户随后发送一个ACK包确认收到了第2个包从而结束连接过程。在收到客户发来的这个SYN/ACK包之后服务器会唤醒一个接收进程等待数据到达。当3次握手完成后客户程序即开始把“有用的”的数据发送给服务器。通常一个HTTP请求的量是很小的而且完全可以装到一个包里。但是在以上的情况下至少有4个包将用来进行双向传输这样就增加了可观的延迟时间。此外你还得注意到在“有用的”数据被发送之前接收方已经开始在等待信息了。 为了减轻这些问题所带来的影响Linux以及其他的一些操作系统在其TCP实现中包括了TCP_DEFER_ACCEPT选项。它们设置在侦听套接字的服务器方该选项命令内核不等待最后的ACK包而且在第1个真正有数据的包到达才初始化侦听进程。在发送SYN/ACK包之后服务器就会等待客户程序发送含数据的IP包。现在只需要在网络上传送3个包了而且还显著降低了连接建立的延迟对HTTP通信而言尤其如此。 这一选项在好些操作系统上都有相应的对等物。例如在FreeBSD上同样的行为可以用以下代码实现 struct accept_filter_arg af { dataready, }; setsockopt(s, SOL_SOCKET, SO_ACCEPTFILTER, af, sizeof(af)); 这个特征在FreeBSD上叫做“接受过滤器”而且具有多种用法。不过在几乎所有的情况下其效果与TCP_DEFER_ACCEPT是一样的服务器不等待最后的ACK包而仅仅等待携带数据负载的包。要了解该选项及其对高性能Web服务器的重要意义的更多信息请参考Apache文档上的有关内容。 就HTTP客户/服务器交互而言有可能需要改变客户程序的行为。客户程序为什么要发送这种“无用的”ACK包呢这是因为TCP协议栈无法知道ACK包的状态。如果采用FTP而非HTTP那么客户程序直到接收了FTP服务器提示的数据包之后才发送数据。在这种情况下延迟的ACK将导致客户/服务器交互出现延迟。为了确定ACK是否必要客户程序必须知道应用程序协议及其当前状态。这样修改客户行为就成为必要了。 对Linux客户程序来说我们还可以采用另一个选项它也被叫做TCP_DEFER_ACCEPT。我们知道套接字分成两种类型侦听套接字和连接套接字所以它们也各自具有相应的TCP选项集合。因此经常同时采用的这两类选项却具有同样的名字也是完全可能的。在连接套接字上设置该选项以后客户在收到一个SYN/ACK包之后就不再发送ACK包而是等待用户程序的下一个发送数据请求因此服务器发送的包也就相应减少了。 TCP_QUICKACK 阻止因发送无用包而引发延迟的另一个方法是使用TCP_QUICKACK选项。这一选项与TCP_DEFER_ACCEPT不同它不但能用作管理连接建立过程而且在正常数据传输过程期间也可以使用。另外它能在客户/服务器连接的任何一方设置。如果知道数据不久即将发送那么推迟ACK包的发送就会派上用场而且最好在那个携带数据的数据包上设置ACK标志以便把网络负载减到最小。当发送方肯定数据将被立即发送多个包时TCP_QUICKACK选项可以设置为0。对处于“连接”状态下的套接字该选项的缺省值是1首次使用以后内核将把该选项立即复位为1这是个一次性的选项。 在某些情形下发出ACK包则非常有用。ACK包将确认数据块的接收而且当下一块被处理时不至于引入延迟。这种数据传输模式对交互过程是相当典型的因为此类情况下用户的输入时刻无法预测。在Linux系统上这就是缺省的套接字行为。 在上述情况下客户程序在向服务器发送HTTP请求而预先就知道请求包很短所以在连接建立之后就应该立即发送这可谓HTTP的典型工作方式。既然没有必要发送一个纯粹的ACK包所以设置TCP_QUICKACK为0以提高性能是完全可能的。在服务器方这两种选项都只能在侦听套接字上设置一次。所有的套接字也就是被接受呼叫间接创建的套接字则会继承原有套接字的所有选项。 通过TCP_CORK、TCP_DEFER_ACCEPT和TCP_QUICKACK选项的组合参与每一HTTP交互的数据包数量将被降低到最小的可接受水平根据TCP协议的要求和安全方面的考虑。结果不仅是获得更快的数据传输和请求处理速度而且还使客户/服务器双向延迟实现了最小化。 关于这些选项的详细情况请查看 Linux Programmers Manual 如下内容转自http://hi.baidu.com/taozpwater/item/55983ec132eb304fa8ba9423 今天发现setsockopt的用法太强大了现在记录下该函数的使用方法 简述 setsockopt函数用于设置套接口的选项。 函数定义如下 int setsockopt( __in SOCKET s, __in int level, __in int optname, __in const char *optval, __in int optlen ); s标识一个套接口的描述字。level选项定义的层次目前仅支持SOL_SOCKET、IPPROTO_TCP、NSPROTO_IPX层次。optname需设置的选项。optval指针指向存放选项值的缓冲区。optlenoptval缓冲区长度。 详解 level SOL_SOCKET SO_BROADCAST BOOL 允许套接口传送广播信息 SO_CONDITIONAL_ACCEPT BOOL Enables incoming connections are to be accepted or rejected by the application, not by the protocol stack. SO_DEBUG BOOL 记录调试信息 SO_DONTLINGER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。 SO_DONTROUTE BOOL 禁止选径直接传送。This option is not supported on ATM sockets (results in an error). SO_GROUP_PRIORITY int Reserved. SO_KEEPALIVE BOOL 发送“保持活动”包。 Not supported on ATM sockets (results in an error). SO_LINGER LINGER Lingers on close if unsent data is present. SO_OOBINLINE BOOL Indicates that out-of-bound data should be returned in-line with regular data. This option is only valid for connection-oriented protocols that support out-of-band data. For a discussion of this topic, see Protocol Independent Out-Of-band Data. SO_RCVBUF int 为接收确定缓冲区大小 SO_REUSEADDR BOOL Allows the socket to be bound to an address that is already in use. For more information, see bind. Not applicable on ATM sockets. SO_EXCLUSIVEADDRUSE BOOL Enables a socket to be bound for exclusive access. Does not require administrative privilege. SO_RCVTIMEO DWORD Sets the timeout, in milliseconds, for blocking receive calls. SO_SNDBUF int 指定发送缓冲区大小。 SO_SNDTIMEO DWORD The timeout, in milliseconds, for blocking send calls. SO_UPDATE_ACCEPT_CONTEXT int Updates the accepting socket with the context of the listening socket. PVD_CONFIG Service Provider Dependent This object stores the configuration information for the service provider associated with socket s. The exact format of this data structure is service provider specific. level IPPROTO_TCP TCP_NODELAY BOOL 禁止发送合并的Nagle算法。This socket option is included for backward compatibility with Windows Sockets1.1 level IPPROTO_UDP UDP_NOCHECKSUM BOOL When TRUE, UDP datagrams are sent with the checksum of zero. Required for service providers. If a service provider does not have a mechanism to disable UDP checksum calculation, it may simply store this option without taking any action. level NSPROTO_IPX IPX_PTYPE int Sets the IPX packet type. IPX_FILTERPTYPE int Sets the receive filter packet type IPX_STOPFILTERPTYPE int Stops filtering the filter type set with IPX_FILTERTYPE IPX_DSTYPE int Sets the value of the data stream field in the SPX header on every packet sent. IPX_EXTENDED_ADDRESS BOOL Sets whether extended addressing is enabled. IPX_RECVHDRBOOLSets whether the protocol header is sent up on all receive headers. IPX_RECEIVE_BROADCAST BOOL Indicates broadcast packets are likely on the socket. Set to TRUE by default. Applications that do not use broadcasts should set this to FALSE for better system performance. IPX_IMMEDIATESPXACK BOOL Directs SPX connections not to delay before sending an ACK. Applications without back-and-forth traffic should set this to TRUE to increase performance. level IPPROTO_IP IP_ADD_MEMBERSHIP struct ip_mreq Joins the socket to multicast group on the specified interface. IP_DROP_MEMBERSHIP struct ip_mreq Leaves the specified multicast group from the specified interface. Service providers must support this option when multicast is supported. Support is indicated in the WSAPROTOCOL_INFO structure returned by a WSAEnumProtocols function call with the following: XPI_SUPORTS_MULTIPOINT1, XP1_MULTIPOINT_CONTROL_PLANE0, XP1_MULTIPOINT_DATA_PLANE0. IP_MULTICAST_IF DWORD Sets the outgoing (IPv4) interface for multicast traffic. Important for multihomed machines. The input value is the 4-byte network byte order IPv4 address. If optval is null, the default interface is used. IP_MULTICAST_TTL DWORD Sets/gets the TTL value associated with IP multicast traffic on the socket. level SOL_IRLMP IRLMP_ENUMDEVICES DEVICELIST Returns a list of IrDA device IDs for IR capable devices within range. IRLMP_IAS_QUERY IAS_QUERY Queries IAS on a given service and class name for its attributes. IRLMP_IAS_SET IAS_SET Enables an application to set a single class in the local IAS. The application specifies the class to set, the attribute, and attribute type. IRMP_IRLPT_MODE int Disables TinyTP mode and sends data directly over IrLMP frames. IRLMP_EXCLUSIVE_MODE int Sets socket to bypass TinyTP layer to directly communicate with IrLMP IRLMP_9WIRE_MODE int Puts the IrDA socket into IrCOMM mode IRLMP_SHARP_MODE int Enables the Sharp mode. IRLMP_SEND_PDU_LEN int Retrieves the maximum PDU length required to use IRLMP_9WIRE_MODE IPV6_ADD_MEMBERSHIP struct ipv6_mreq Join the supplied multicast group on the given interface index IPV6_DROP_MEMBERSHIP struct ipv6_mreq Leave the supplied multicast group from the given interface IPV6_HDRINCL BOOL Indicates IPv6 header will be supplied on all outgoing data IPV6_HOPLIMIT BOOL Indicates that hop (TTL) information should be returned in the WSARecvMsg function IPV6_JOIN_GROUP struct ipv6_mreq Same as IPV6_ADD_MEMBERSHIP IPV6_LEAVE_GROUP struct ipv6_m Same as IPV6_DROP_MEMBERSHIP IPV6_MULTICAST_HOPS DWORD Sets/gets the TTL value associated with IPv6 multicast traffic on the socket IPV6_MULTICAST_IF DWORD Sets the outgoing (IPv6) interface for multicast traffic. This is important for multihomed machines. The input value is the 4-byte interface index of the desired outgoing interface (use GetAdaptersAddresses to obtain index information). IPV6_MULTICAST_LOOP BOOL Indicates multicast data sent on socket will be echoed to the sockets receive buffer if it is also joined on the destination multicast group IPV6_PKTINFO BOOL Indicates that packet information should be returned in the WSARecvMsg function IPV6_PROTECTION_LEVEL INT Enables restriction of a socket to a specified scope, such as addresses with the same link local or site local prefix. Provides various restriction levels and default settings. See Using IPV6_PROTECTION_LEVEL for more information. IPV6_UNICAST_HOPS DWORD Sets/gets the current TTL value associated with IPv6 socket 返回值 若无错误发生setsockopt()返回0。否则的话返回SOCKET_ERROR错误应用程序可通过WSAGetLastError()获取相应错误代码。 错误代码 WSANOTINITIALISED在使用此API之前应首先成功地调用WSAStartup()。 WSAENETDOWNWINDOWS套接口实现检测到网络子系统失效。 WSAEFAULToptval不是进程地址空间中的一个有效部分。 WSAEINPROGRESS一个阻塞的WINDOWS套接口调用正在运行中。 WSAEINVALlevel值非法或optval中的信息非法。 WSAENETRESET当SO_KEEPALIVE设置后连接超时。 WSAENOPROTOOPT未知或不支持选项。其中SOCK_STREAM类型的套接口不支持SO_BROADCAST选项SOCK_DGRAM类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。 WSAENOTCONN当设置SO_KEEPALIVE后连接被复位。 WSAENOTSOCK描述字不是一个套接口。 实例 1.设置调用closesocket()后,仍可继续重用该socket。调用closesocket()一般不会立即关闭socket而经历TIME_WAIT的过程。 BOOL bReuseaddr TRUE; setsockopt( s, SOL_SOCKET, SO_REUSEADDR, ( const char* )bReuseaddr, sizeof( BOOL ) ); 2. 如果要已经处于连接状态的soket在调用closesocket()后强制关闭不经历TIME_WAIT的过程 BOOL bDontLinger FALSE; setsockopt( s, SOL_SOCKET, SO_DONTLINGER, ( const char* )bDontLinger, sizeof( BOOL ) ); 3.在send(),recv()过程中有时由于网络状况等原因收发不能预期进行,可以设置收发时限 int nNetTimeout 1000; //1秒 //发送时限 setsockopt( socket, SOL_SOCKET, SO_SNDTIMEO, ( char * )nNetTimeout, sizeof( int ) ); //接收时限 setsockopt( socket, SOL_SOCKET, SO_RCVTIMEO, ( char * )nNetTimeout, sizeof( int ) ); 4.在send()的时候返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步)系统默认的状态发送和接收一次为8688字节(约为8.5K)在实际的过程中如果发送或是接收的数据量比较大可以设置socket缓冲区避免send(),recv()不断的循环收发 // 接收缓冲区 int nRecvBuf 32 * 1024; //设置为32K setsockopt( s, SOL_SOCKET, SO_RCVBUF, ( const char* )nRecvBuf, sizeof( int ) ); //发送缓冲区 int nSendBuf 32*1024; //设置为32K setsockopt( s, SOL_SOCKET, SO_SNDBUF, ( const char* )nSendBuf, sizeof( int ) ); 5.在发送数据的时不执行由系统缓冲区到socket缓冲区的拷贝以提高程序的性能 int nZero 0; setsockopt( socket, SOL_S0CKET, SO_SNDBUF, ( char * )nZero, sizeof( nZero ) ); 6.在接收数据时不执行将socket缓冲区的内容拷贝到系统缓冲区 int nZero 0; setsockopt( s, SOL_S0CKET, SO_RCVBUF, ( char * )nZero, sizeof( int ) ); 7.一般在发送UDP数据报的时候希望该socket发送的数据具有广播特性 BOOL bBroadcast TRUE; setsockopt( s, SOL_SOCKET, SO_BROADCAST, ( const char* )bBroadcast, sizeof( BOOL ) ); 8.在client连接服务器过程中如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被调用(此设置只有在非阻塞的过程中有显著的作用在阻塞的函数调用中作用不大) BOOL bConditionalAccept TRUE; setsockopt( s, SOL_SOCKET, SO_CONDITIONAL_ACCEPT, ( const char* )bConditionalAccept, sizeof( BOOL ) );