服务器编程入门(13) Linux套接字设置超时的三种方法
摘要:
本文介绍在套接字的I/O操作上设置超时的三种方法。

图片可能有点宽,看不到的童鞋可以点击图片查看完整图片。。
1 调用alarm
使用SIGALRM为connect设置超时
设置方法:
- 监听SIGALRM信号,
- 设置sig_alrm处理函数,
- 在阻塞函数前调用alarm函数设置超时时间,
- 正常返回后,重置超时事件为0
void handle_msg(int sockfd) {
char sendbuf[BUFSIZE];
char recvbuf[BUFSIZE];
signal(SIGALRM, sig_alrm); //监听SIGALRM信号
while(1) {
memset( sendbuf, '\0', BUFSIZE );
memset( recvbuf, '\0', BUFSIZE );
printf("%s", "send msg:");
gets(sendbuf);
if (strlen(sendbuf) > 0)
send(sockfd,sendbuf,strlen(sendbuf),0);
if ( !strcmp(sendbuf, "exit"))
break;
alarm(5); //设置超时事件为5s,同时设置服务器回射前sleep 10秒,以让recv函数超时
if (recv(sockfd,recvbuf,BUFSIZE,0) > 0) {
alarm(0);
printf("recv back:%s\n\n", recvbuf);
}
else {
if (errno == EINTR)
fprintf(stderr,
"socket timeout\n");
else
fprintf(stderr,
"receive error\n");
}
}
close( sockfd );
return;
}
static void sig_alrm(int signo) {
fprintf(stderr,
"recv SIGALRM, return.\n");
return;
}
运行截图:

虽然设置了SIGALRM信号处理函数,但是如图所示,本例依然可以等待读取回射信息,因为信号处理函数里只是return。
2 使用select阻塞等待I/O
设置方法:
使用select的内置时间限制,阻塞在select代替recv函数的阻塞。
void handle_msg(int sockfd) {
char sendbuf[BUFSIZE];
char recvbuf[BUFSIZE];
while(1) {
memset( sendbuf, '\0', BUFSIZE );
memset( recvbuf, '\0', BUFSIZE );
printf("%s", "send msg:");
gets(sendbuf);
if (strlen(sendbuf) > 0)
send(sockfd,sendbuf,strlen(sendbuf),0);
if ( !strcmp(sendbuf, "exit"))
break;
if (readable_timeo(sockfd, 5) == 0) {
fprintf(stderr,
"socket timeout\n");
}
else{
recv(sockfd,recvbuf,BUFSIZE,0);
printf("recv back:%s\n\n", recvbuf);
}
}
close( sockfd );
return;
}
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);
}
运行截图:

由运行截图可以看到,超时警告运行正常。
需要注意一点的是,虽然客户端在超时之后继续发送消息,但是服务器回射的消息(hello world)依然被接收,这导致我们再次发送消息时,从缓冲区中读出了延迟收到的hello world。
这里只是演示超时技术,因此对此并不做进一步处理。
3 使用SO_RCVTIMEO套接字选项
使用SO_RCVTIMEO套接字选项为recv设置超时
设置方法:
- 使用setsockopt函数对套接字进行设置
- 一旦设置了某个描述符,其超时设置将应用于该描述符上的所有读操作
- SO_RCVTIMEO仅用于读操作,SO_SNDTIMEO仅用于写操作,两者都不能用于为connect设置超时
- 如果套接字超时,被阻塞的函数将返回一个EWOULDBLOCK错误
void handle_msg(int sockfd) {
char sendbuf[BUFSIZE];
char recvbuf[BUFSIZE + 1];
int n;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO,
&tv, sizeof(tv) );
while(1) {
memset( sendbuf, '\0', BUFSIZE );
memset( recvbuf, '\0', BUFSIZE );
printf("%s", "send msg:");
gets(sendbuf);
if (strlen(sendbuf) > 0)
send(sockfd,sendbuf,strlen(sendbuf),0);
if ( !strcmp(sendbuf, "exit"))
break;
if ( (n=recv(sockfd,recvbuf,BUFSIZE,0)) < 0 ) {
if (errno == EWOULDBLOCK) {
fprintf(stderr,
"socket timeout\n");
continue;
}
else
fprintf(stderr,
"recv error");
}
else{
printf("recv back:%s\n\n", recvbuf);
}
}
close( sockfd );
return;
}
运行截图:

可以看到,超时警报成功运行,但依然有上一例中的延迟接收的情况发生,不作处理。
示例源码上传到了github上,地址:https://github.com/zs634134578/UNP/tree/tryTimeout
参考资料:
《UNIX网络编程 卷1:套接字联网API(第3版)》
服务器编程入门(13) Linux套接字设置超时的三种方法的更多相关文章
- Unix网络编程 高级IO套接字设置超时
我们知道.对于一个套接字的读写(read/write)操作默认是堵塞的.假设当前套接字还不可读/写,那么这个操作会一直堵塞下去,这样对于一个须要高性能的server来说,是不能接受的.所以,我们能够在 ...
- linux设置变量的三种方法
1在/etc/profile文件中添加变量对所有用户生效(永久的) 用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久生效”. 例如:编辑/etc/ ...
- linux下修改.bash_profile立即生效的三种方法
1 . .bash_profile 2 source .bash_profile 3 exec bash --login
- 详解linux下批量替换文件内容的三种方法(perl,sed,shell)
在建设本网站的时候,发现新建了很多的网页,突然发现,每个文件都需要进行修改一样的内容,一个一个打开很是麻烦,所以,总结了一下如何快速修改一个目录下多个文件进行内容替换.第三种方法用的不多 方法一 使用 ...
- linux清空文件内容的三种方法
linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...
- linux 套接字编程入门--Hello World
下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...
- Linux 套接字编程中的 5 个隐患(转)
本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...
- 第13讲 | 套接字Socket:Talk is cheap, show me the code
第13讲 | 套接字Socket:Talk is cheap, show me the code 基于 TCP 和 UDP 协议的 Socket 编程.在讲 TCP 和 UDP 协议的时候,我们分客户 ...
- [转载] 读《UNIX网络编程 卷1:套接字联网API》
原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/ 文章写的很清楚, 适合初学者 最近看了<UNIX网 ...
随机推荐
- 使用Thumbnailator处理gif图片时遇到java.lang.ArrayIndexOutOfBoundsException: 4096异常处理
环境 1.7.0_80 在使用Thumbnailator处理gif图片时,遇到问题: Exception in thread "main" java.lang.ArrayIndex ...
- R语言格式化数字和字符串format函数
数字和字符串可以使用 format()函数的格式化为特定样式. 语法 format()函数的基本语法是: format(x, digits, nsmall,scientific,width,justi ...
- android studio导入android studio工程
在导入其他android studio工程的时候因为gradle和sdk.tool等版本不一样,会导致android studio自动去后台下载,导致占用硬盘越来越大,最主要的时候会等待很久,不知道要 ...
- SVN使用指南
一:SVN服务器搭建和使用. 1. 首先来下载和搭建SVN服务器,下载地址如下: http://subversion.apache.org/packages.html,进入网址后,滚动到浏览器 ...
- PL/SQL之游标的使用
Oracle中的游标有两种: 显式游标 用CURSOR...IS 命令定义的游标,它可以对查询语句(SELECT)返回的多条记录进行处理. 隐式游标 是在执行插入(INSERT).删除(DELETE) ...
- nodejs记录1——async函数
其实手动配置babel环境并不难,记录下步骤: 1.首先npm init创建一个nodejs项目 2.全局安装babel-cli处理工具:npm i babel-cli -g 3.cd到项目下安装ba ...
- [javaSE] 数据结构(二叉树-遍历与查找)
前序遍历:中,左,右 中序遍历:左,中,右 后序遍历:左,右,中 二叉树查找 从根节点进行比较,目标比根节点小,指针移动到左边 从根节点进行比较,目标比根节点大,指针移动到右边 /** * 前序遍历 ...
- Java基础教程(6)--数组
1.基本概念 数组中的每一项称为元素,每个元素都通过数字索引(也可以称为下标)访问,编号从0开始.例如,第4个元素的索引为3.下面的程序创建了一个int类型的数组,把一些值放入数组中并将每个值打印 ...
- 中小型研发团队架构实践三:微服务架构(MSA)
一.MSA 简介 1.1.MSA 是什么 微服务架构 MSA 是 Microservice Architect 的简称,它是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相通讯.互相 ...
- Access MetaData
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...