摘要:

    本文介绍在套接字的I/O操作上设置超时的三种方法。


图片可能有点宽,看不到的童鞋可以点击图片查看完整图片。。


1 调用alarm

使用SIGALRM为connect设置超时

设置方法:

  1. 监听SIGALRM信号,
  2. 设置sig_alrm处理函数,
  3. 在阻塞函数前调用alarm函数设置超时时间,
  4. 正常返回后,重置超时事件为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套接字设置超时的三种方法的更多相关文章

  1. Unix网络编程 高级IO套接字设置超时

    我们知道.对于一个套接字的读写(read/write)操作默认是堵塞的.假设当前套接字还不可读/写,那么这个操作会一直堵塞下去,这样对于一个须要高性能的server来说,是不能接受的.所以,我们能够在 ...

  2. linux设置变量的三种方法

    1在/etc/profile文件中添加变量对所有用户生效(永久的) 用VI在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久生效”. 例如:编辑/etc/ ...

  3. linux下修改.bash_profile立即生效的三种方法

    1 . .bash_profile 2 source .bash_profile 3 exec bash --login

  4. 详解linux下批量替换文件内容的三种方法(perl,sed,shell)

    在建设本网站的时候,发现新建了很多的网页,突然发现,每个文件都需要进行修改一样的内容,一个一个打开很是麻烦,所以,总结了一下如何快速修改一个目录下多个文件进行内容替换.第三种方法用的不多 方法一 使用 ...

  5. linux清空文件内容的三种方法

    linux系统中清空文件内容的三种方法 1.使用vi/vim命令打开文件后,输入"%d"清空,后保存即可.但当文件内容较大时,处理较慢,命令如下:vim file_name:%d: ...

  6. linux 套接字编程入门--Hello World

    下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...

  7. Linux 套接字编程中的 5 个隐患(转)

    本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...

  8. 第13讲 | 套接字Socket:Talk is cheap, show me the code

    第13讲 | 套接字Socket:Talk is cheap, show me the code 基于 TCP 和 UDP 协议的 Socket 编程.在讲 TCP 和 UDP 协议的时候,我们分客户 ...

  9. [转载] 读《UNIX网络编程 卷1:套接字联网API》

    原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/ 文章写的很清楚, 适合初学者 最近看了<UNIX网 ...

随机推荐

  1. 【数组】Unique Paths II

    题目: Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. H ...

  2. JavaScript数据结构-9.循环链表

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 向div添加圆角边框

    初级参数:border-radius: 4px;中级参数:border-radius: 4px 6px 6px 4px;终极参数:border-radius: 5px 5px 3px 2px / 5p ...

  4. 微服务Kong(七)——CLI参考

    KONG提供了一套CLI(命令行界面)命令,您可以通过它来启动.停止和管理您的Kong实例.CLI管理您的本地节点(如在当前机器上). 全局配置 所有命令都采用一组指定的可选标志作为参数: --hel ...

  5. JDK源码--ArrayList浅析

    先上别人的源码分析http://www.cnblogs.com/roucheng/p/jdkfenxi.html 这个链接也不错:http://www.jianshu.com/p/8d14b55fa1 ...

  6. flash builder注释字体看不清

    window-preferences-flex-editiors-syntex coloring-ActionScript-Comment (窗口-首选项-flashbuilder-编辑器-语法着色- ...

  7. 清空控件的TeXt属性

    foreach (Control item in groupBox1.Controls) { if (item is TextBox) //判断控件是不是TextBox { item.Text = & ...

  8. DataGridView 隔行显示不同的颜色

    两种方法 第一种 DataGridview1.Rows[i].DefultCellStyle.backcolor 第二种 AlternatingRowsDefutCellstyle 属性 获取或设置应 ...

  9. GridFS使用及配合nginx实现文件服务

    Mongodb下GridFS使用及配合nginx实现文件服务 一.GridFS简介 GridFS是mongodb下用来存储文件的一种规范,所有官方支持的驱动均实现了GridFS规范. Mongodb本 ...

  10. [javaSE] GUI(对话框Dialog)

    对话框不能单独存在,依赖于窗体,有显示标题,有模式 获取Dialog对象,new出来,构造参数:Frame对象,String的标题,模式 窗体内部的内容,Label对象,Button对象,调用Dial ...