Unix网络编程 高级IO套接字设置超时
我们知道。对于一个套接字的读写(read/write)操作默认是堵塞的。假设当前套接字还不可读/写,那么这个操作会一直堵塞下去,这样对于一个须要高性能的server来说,是不能接受的。所以,我们能够在进行读写操作的时候能够指定超时值,这样就读写操作就不至于一直堵塞下去。
在涉及套接字的I/O操作上设置超时的方法有三种:
1:调用alarm,它在指定的超时期满时产生SIGALRM信号。这种方法涉及信号处理,而信号处理在不同的实现上存在差异,并且可能干扰进程中现有的alarm调用。
2:在select中堵塞等待I/O(select有内置的时间限制),依次取代直接堵塞在read或write调用上。(linux2.6以后的内核也能够使用epoll的epoll_wait)。
3:使用较新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这种方法的问题在于并不是全部的实现都支持这两个套接字选项。
上述这三个技术都适用于输入和输出操作(read、write。及其变体recv/send, readv/writev, recvfrom, sendto)。
只是我们也期待能够用于connect的技术,由于TCP内置的connect超时相当长(典型值为75秒),而我们在写server程序的时候,也不会希望一个连接的建立须要花费这么长时间。
select可用来在connect上设置超时的先决条件是对应的套接字是非堵塞的。而那两个套接字选项对connect并不适用。同一时候也应当指出,前两个技术适用于不论什么描写叙述符。而第三个技术只适用于套接字描写叙述符。
>>>>使用select对connect设置超时:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <time.h>
#define PORT 9900
#define MAXDATASIZE 5000 int main(int argc, char **argv)
{
int sockfd, nbytes;
char buf[1024];
struct hostent *he;
struct sockaddr_in servaddr; if(argc != 2) {
perror("Usage:client hostname\n");
return 0;
}
if((he = gethostbyname(argv[1])) == NULL) {
perror("gethostbyname");
return 0;
}
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("create socket error");
return 0;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr = *((struct in_addr *)he->h_addr);
fcntl(sockfd, F_SETFL, O_NONBLOCK);
timeval timeout = {3, 0};
if(connect(sockfd, (SA*)&servaddr, sizeof(struct sockaddr)) == -1) {
if(errno != EINPROGRESS) {
close(sockfd);
perror("connect error");
return 0;
}
} fd_set readSet;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_SET(sockfd, &writeSet);
int ret = select(sockfd+1, &readSet, &writeSet, NULL, &timeout);
printf("%d", ret);
}
>>>>使用SIGALRM为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 = ETIMEOUT;
}
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() */
}
>>>>使用SIGALRM为recvfrom设置超时:
#include <unp.h> static void sig_alarm(int); void
dig_cli(FILE* fp, int sockfd, const SA* pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE+1]; Signal(SIGALRM, sig_alarm); while(Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen);
alarm(5); /* set TIMEOUT 5 seconds */
if((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
if(errno == EINTR)
fprintf(stderr, "socket timeout\n");
else
err_sys("recvfrome error");
}else {
alarm(0); /* if success then turn off the alarm */
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
} static void
sig_alarm(int signo)
{
return ; /* just interrupt the recvfrom() */
}
>>>>使用select为recvfrom设置超时:
#include <unp.h> int
readable_timeo(int fd, int sec)
{
fd_set rset;
struct timeval tv; FD_ZERO(&rset); /* reset the file discriptor set */
FD_SET(fd, &rset); tv.tv_sec = sec; /* set struct timeval */
tv.tv_usec = 0; return (select(fd+1, &rset, NULL, NULL, &tv));
}
所以上面dig_cli函数结合readable_timeo函数设置超时的程序就可变为:(堵塞在select上)
#include <unp.h> void
dig_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, preservaddr, serlen);
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);
}
}
}
>>>>使用SO_RCVTIMEO套接字选项为recvfrom设置超时:
#include <unp.h> void
dig_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, &tv, sizeof(tv)); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); 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);
}
}
Unix网络编程 高级IO套接字设置超时的更多相关文章
- Unix网络编程--卷一:套接字联网API
UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...
- 【Unix网络编程】chapter3套接字编程简介
chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...
- 【Unix网络编程】chapter3 套接字编程简介
chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...
- UNIX网络编程——基本TCP套接字编程
一.基于TCP协议的网络程序 下图是基于TCP协议的客户端/服务器程序的一般流程: 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听端口的 ...
- 【Unix网络编程】chapter7套接字选项
7.1 概述 有很多方法来获取和设置影响套接字的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 7.2 getsockopt和setsockopt函数 7.3 ...
- Linux网络编程:原始套接字简介
Linux网络编程:原始套接字编程 一.原始套接字用途 通常情况下程序员接所接触到的套接字(Socket)为两类: 流式套接字(SOCK_STREAM):一种面向连接的Socket,针对于面向连接的T ...
- VC++学习之网络编程中的套接字
VC++学习之网络编程中的套接字 套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程.应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问 ...
- 网络编程与socket套接字
网络编程与socket套接字 传输层 PORT协议 port是一种接口,数据通过它在计算机和其他设备(比如打印机,鼠标,键盘或监视器)之间,网络之间和其他直接连接的计算机之间传递 TCP协议 传输 ...
- 服务器编程入门(13) Linux套接字设置超时的三种方法
摘要: 本文介绍在套接字的I/O操作上设置超时的三种方法. 图片可能有点宽,看不到的童鞋可以点击图片查看完整图片.. 1 调用alarm 使用SIGALRM为connect设置超时 设置方法: ...
随机推荐
- B树、B+树、红黑树、AVL树比较
B树是为了提高磁盘或外部存储设备查找效率而产生的一种多路平衡查找树. B+树为B树的变形结构,用于大多数数据库或文件系统的存储而设计. B树相对于红黑树的区别 在大规模数据存储的时候,红黑树往往出现由 ...
- 开发日记(项目中SQL查询的优化)
今天发现自己之前写的一些SQL查询在执行效率方面非常不理想,于是尝试做了些改进. 需求为查询国地税表和税源表中,国税有而税源没有的条目数,之前的查询如下: SELECT COUNT(NAME) ...
- c++ 以二进制和以文本方式读写文件的区别
在c++项目开发中,时常涉及到文件读写操作.因此在这里先简单梳理和回顾一下文本模式和二进制模式在进行文件读写上的区别. 1.linux平台下文本文件和二进制文件的读写 在linux平台下进行文件读写时 ...
- Detectron-MaskRCnn: 用于抠图的FCNN
市面上暂时还没有找到可以在消费机显卡上实时运行的MaskRCnn,TensorFlow即使是C++版本训练在coco数据集上的模型也是慢的要死,最后不堪忍受,只能放弃. 经历了一些列fuckingDo ...
- log4j最全教程
(转自http://www.codeceo.com/article/log4j-usage.html) 日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方 ...
- layer:好看的弹出窗口
layer是一款web弹层组件,只需在调用时简单地配置相关参数,即可轻松实现丰富与便捷的操作体验. 这是layer的官方地址,里面的使用介绍非常详细(http://layer.layui.com/) ...
- java主要集合类的数据结构
1).ArrayList ArrayList维护着一个对象数组.如果调用new ArrayList()后,它会默认初始一个size=10的数组. 每次add操作都要检查数组容量,如果不够,重新 ...
- VBA/VBScript提取Word(*.doc)文件中包含的图片(照片)
VBA/VBScript提取Word(*.doc)文件中包含的图片(照片) 要处理的人事简历表是典型的Word文档,其中一人一份doc,里面包含有个人的照片,如果要把里面的照片复制出来就比较麻烦了 ...
- eclipse Errors during build
eclipse在运行main方法或者运行ant里的clean方法时,总是会报下面的错,需要点击第二次才能正常运行 今天终于把这个问题解决了,解决方案如下 项目右键,点properties 点击buil ...
- pycharm执行代码可以跑,但放到linux跑就报文件找不到
代码中包含当前路径 使用pycharm执行python,当前路径就是pycharm项目所在的路径,所以不会报错 但使用shell执行python,当前路径就会从shell所在的路径去找文件,所以找不到 ...