UNIX网络编程——设置套接字超时
在涉及套接字的I/O操作上设置超时的方法有以下3种:
- 调用alarm,它在指定超时期时产生SIGALRM信号。这个方法涉及信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有的alarm调用。
- 在select中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在read或write调用上。
- 使用较新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于,并非所有实现都支持这两个套接字选项。
1.使用SIGALRM为connect设置超时
如下给出我们的connect_timeo函数,它以由调用者指定的超时上限调用connect。它的前3个参数用于调用connect,第四个参数是等待的秒数。
#include "unp.h" static void connect_alarm(int); int
connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
sigfunc *sigfunc;
int n; sigfunc = signal(SIGALRM, connect_alarm);
if (alarm(nsec) != 0)
err_msg("connect_timeo: alarm was already set"); if ( (n = connect(sockfd, saptr, salen)) < 0) {
close(sockfd);
if (errno == EINTR)
errno = ETIMEDOUT;
}
alarm(0); /* turn off the alarm */
signal(SIGALRM, sigfunc); /* restore previous signal handler */ return(n);
} static void
connect_alarm(int signo)
{
return; /* just interrupt the connect() */
}
12-13 把本进程的报警时钟设置成由调用者指定的秒数。如果此前已经给本进程时钟过报警时钟,那么alarm的返回值是现在设置的新值,否则alarm的返回值为0.
15-19 调用connect,如果本调用被中断(即返回EINTR错误),那就把errno值改设为ETIMEOUT,同时关闭套接字,以防三路握手继续进行。
20-21 通过以0为参数值调用alarm关闭本进程的报警时钟,同时恢复原来的信号处理函数(如果有的话)。
就本例子我们指出两点:
- 使用本技术总能减少connect的超时期限,但是无法延长内核现有的超时。源自Berkeley的内核中connect的超时通常为75s。在调用我们的函数时,可以指定一个比75小的值,但是如果指定一个比75大的值,那么connect仍将在75s后发生超时。
- 我们使用了系统调用(connect)的可中断能力,使得他们能够在内核超时发生之前返回。这一点不成问题的前提是:我们执行的是系统调用,并且能够直接处理由他们返回的EINTR错误。
2.使用SIGALRM为recvfrom设置超时
dg_cli函数通过调用alarm使得一旦在5S内收不到任何应答就中断recvfrom。
#include "unp.h" static void sig_alrm(int); void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1]; signal(SIGALRM, sig_alrm); while (fgets(sendline, MAXLINE, fp) != NULL) { sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); alarm(5);
if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
if (errno == EINTR)
fprintf(stderr, "socket timeout\n");
else
err_sys("recvfrom error");
} else {
alarm(0);
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
}
} static void
sig_alrm(int signo)
{
return; /* just interrupt the recvfrom() */
}
11-28 为SIGALRM建立一个信号处理函数,并在每次调用recvfrom前通过调用alarm设置一个5S的超时。如果recvfrom被我们的信号处理函数中断了,那
就输出一个信息并继续执行。如果读到一行来自服务器的文本,那就关掉报警时钟并输出服务器的应答。
31-35 信号处理函数只是简单的返回,以中断被阻塞的recvfrom。
3.使用select为recvfrom设置超时
readable_timeo的函数等待一个描述符最多在指定的秒数内变为可读。
#include "unp.h" int
readable_timeo(int fd, int sec)
{
fd_set rset;
struct timeval tv; FD_ZERO(&rset);
FD_SET(fd, &rset); tv.tv_sec = sec;
tv.tv_usec = 0; return(select(fd+1, &rset, NULL, NULL, &tv));
/* 4> 0 if descriptor is readable */
}
9-13 在读描述符集中打开与调用者给定描述符对应的位。把调用者给定的等待秒数设置在一个timeval结构中。
15 select等待该描述符变为可读或者发生超时。本函数的返回值就是select的返回值:出错时为-1,超时发生时为0,否则返回的正值给出已就绪描述符的数目。
#include "unp.h" void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1]; while (fgets(sendline, MAXLINE, fp) != NULL) { sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); if (readable_timeo(sockfd, 5) == 0) {
fprintf(stderr, "socket timeout\n");
} else {
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
}
}
4.使用SO_RCVTIMEO套接字选项为recvfrom设置超时
SO_RCVTIMEO套接字选项一旦设置到某个描述符(包括指定超时值),其超时设置将应用于该描述符上的所有读操作。本方法的优势就体现在一次性设置选项上,而前两个方法总是要求我们在欲设置时间限制的每个操作发生之前做些工作。本套接字选项仅仅应用于读操作,类似的SO_SNDTIMEO选项则仅仅应用于写操作,两者都不能用于为connect设置超时。
#include "unp.h" void dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
struct timeval tv; tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); while (fgets(sendline, MAXLINE, fp) != NULL) { sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
if (n < 0) {
if (errno == EWOULDBLOCK) {
fprintf(stderr, "socket timeout\n");
continue;
} else
err_sys("recvfrom error");
} recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
}
9-11 setsockopt的第四个参数是指向某个timeval结构的一个指针,其中填入了期望的超时值。
18-21 如果I/O操作超时,其函数(这里是recvfrom)将返回一个EWOULDBLOCK错误。
UNIX网络编程——设置套接字超时的更多相关文章
- UNIX网络编程——原始套接字(dos攻击)
原始套接字(SOCK_RAW).应用原始套接字,我们可以编写出由TCP和UDP套接字不能够实现的功能. 注意原始套接字只能够由有 root权限的人创建. 可以参考前面的博客<<UNIX网络 ...
- UNIX网络编程——原始套接字的魔力【续】
如何从链路层直接发送数据帧 上一篇里面提到的是从链路层"收发"数据,该篇是从链路层发送数据帧. 上一节我们主要研究了如何从链路层直接接收数据帧,可以通过bind函数来将原始套接字绑 ...
- UNIX网络编程——原始套接字的魔力【上】
基于原始套接字编程 在开发面向连接的TCP和面向无连接的UDP程序时,我们所关心的核心问题在于数据收发层面,数据的传输特性由TCP或UDP来保证: 也就是说,对于TCP或UDP的程序开发,焦点在Dat ...
- UNIX网络编程——原始套接字SOCK_RAW
实际上,我们常用的网络编程都是在应用层的报文的收发操作,也就是大多数程序员接触到的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM).而这些数据包都是由系统提供的协议栈实现, ...
- UNIX网络编程——通用套接字选项
1. SO_BROADCAST 套接字选项 本选项开启或禁止进程发送广播消息的能力.只有数据报套接字支持广播,并且还必须是在支持广播消息的网络上(例如以太网,令牌环网等).我们不可能在点对点链路上进行 ...
- unix网络编程——TCP套接字编程
TCP客户端和服务端所需的基本套接字.服务器先启动,之后的某个时刻客户端启动并试图连接到服务器.之后客户端向服务器发送请求,服务器处理请求,并给客户端一个响应.该过程一直持续下去,直到客户端关闭,给服 ...
- UNIX网络编程——原始套接字的魔力【下】
可以接收链路层MAC帧的原始套接字 前面我们介绍过了通过原始套接字socket(AF_INET, SOCK_RAW, protocol)我们可以直接实现自行构造整个IP报文,然后对其收发.提醒一点,在 ...
- <unix网络编程>UDP套接字编程
典型的UDP客户/服务器程序的函数调用如下: 1.缓冲区 发送缓冲区用虚线表示,任何UDP套接字都有发送缓冲区,不过该缓冲区仅能表示写到该套接字的UDP数据报的上限.如果应用进程写一个大于套接字缓冲区 ...
- TCP/IP网络编程之套接字类型与协议设置
套接字与协议 如果相隔很远的两人要进行通话,必须先决定对话方式.如果一方使用电话,另一方也必须使用电话,而不是书信.可以说,电话就是两人对话的协议.协议是对话中使用的通信规则,扩展到计算机领域可整理为 ...
随机推荐
- NTT+多项式求逆+多项式开方(BZOJ3625)
定义多项式$h(x)$的每一项系数$h_i$,为i在c[1]~c[n]中的出现次数. 定义多项式$f(x)$的每一项系数$f_i$,为权值为i的方案数. 通过简单的分析我们可以发现:$f(x)=\fr ...
- jQuery Datetable
先来个官网可以直接看官网 https://www.datatables.net/manual/data/ 安装 DataTables是一个功能强大的Javascript库,用于为HTML表格添加交互 ...
- java实现生产者/消费者的三种方式
package com.wenki.thread; import java.util.LinkedList; import java.util.concurrent.LinkedBlockingQue ...
- 利用maven install jar到项目当中
接着上面利用maven打好的jar包.把刚刚打好的包放入其他项目当中怎么办? 只需要在相同的目录下执行mvn install,maven会自动把jar放到本地仓库中. 这样,原先maven项目中缺少依 ...
- SQL使用总结-like,MAX,MIN
1. 时间索引不容许使用like 对时间索引适应like,会时间索引变成字符串操作,成为遍历动作,失去索引价值. 错误写法: EXPLAIN SELECT AVG(data_value) AS av ...
- struts2中的使用BaseAction获取Session
package com.owen.ma; import java.util.Map; import org.apache.struts2.interceptor.RequestAware; impor ...
- mysql 索引列为Null的走不走索引及null在统计时的问题
要尽可能地把字段定义为 NOT NULL,即使应用程序无须保存 NULL(没有值),也有许多表包含了可空列(Nullable Column)这仅仅是因为它为默认选项.除非真的要保存 NULL,否则就把 ...
- C# 基础问答
1.静态变量和非静态变量的区别? 2.const 和 static readonly 区别? 3.extern 是什么意思? 4.abstract 是什么意思? 5.internal 修饰符起什么作用 ...
- python学习之路前端-HTML
HTML概述 HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都来遵守他,这样就可以 ...
- Page Object设计模式实践
Page Object模式是使用Selenium的广大同行最为公认的一种设计模式.在设计测试时,把元素和方法按照页面抽象出来,分离成一定的对象,然后再进行组织. Page Object模式,创建一个对 ...