我用select做多路复用踩到的坑
既然说是用select踩到的坑,那么就先直接贴一段使用select的代码上来瞅一下:
bool SocketAction(int fd, const char* buf, size_t len, uint64_t milli_expire) {
struct timeval tv;
tv.tv_sec = milli_expire / 1000;
tv.tv_usec = (milli_expire % 1000) * 1000;
fd_set rd_set, wt_set;
FD_ZERO(&rd_set);
FD_ZERO(&wt_set);
FD_SET(fd, &rd_set);
FD_SET(fd, &wt_set);
int ret = 0;
while (true) {
ret = select(fd+1, &rd_set, &wt_set, nullptr, &tv);
if (ret < 0 && errno == EINTR) continue;
break;
}
if(FD_ISSET(fd, &rd_set)) {
char rd_buf[1024] = {0};
ret = read(fd, rd_buf, sizeof(rd_buf));
if(ret < 0) return false;
printf("%s\n", rd_buf);
} else if(FD_ISSET(fd, &wt_set)) {
ret = send(fd, buf, len, 0);
if(ret < 0) return false;
}
return true;
}
上面的代码着实非常easy,仅仅是针对某一个socket fd进行读写操作,从逻辑上来说应该是没有不论什么问题的。然而这个在实际的使用过程中确实会出现故障。我们程序中封装了socket的操作,如上代码的方式使用了select。
在出现大量的socket连接时,会出现宕机现象,而且宕机生成的core文件的堆栈也莫名其妙的被破坏了。
遇到这个情况时。我直接被震惊了,由于细致检查了代码确实没有发现不论什么问题。为什么每次都是连接数达到快1500的时候就出现宕机呢?
刚開始以为是其它的逻辑出了问题。于是细致检查了其它的逻辑确实也没有发现存在不论什么问题,而且从堆栈被破坏的情况上分析,也怀疑是某个使用中出现了数组越界訪问引发的。但在整个逻辑中使用的都是stl里的容器,没有申请数组,出现读写越界着实无法理解。
此后仅仅能怀疑底层封装的问题。在一步步尝试凝视代码的过程中。发现select使用的地方出现了问题。那么问题到底在哪里呢?
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
在select的使用manual中,select的定义和nfds的说明如上所看到的。也仅仅是说明了select的nfds是最大的文件描写叙述符+1。在实际的使用过程中也确实有这么使用。好像也确实没有问题。然而,不止这么简单。select的文件描写叙述符的最大值实际是有一个潜在规则的。那就是select的最大文件描写叙述符最大是1024。该值在centor os系统中。定义在文件/usr/include/sys/select.h文件里。例如以下:
78 /* Maximum number of file descriptors in `fd_set'. */
79 #define FD_SETSIZE __FD_SETSIZE
而__FD_SETSIZE则定义在:/usr/include/bits/typesizes.h 中,例如以下:
62 /* Number of descriptors that can fit in an `fd_set'. */
63 #define __FD_SETSIZE 1024
这下能够理解了吧。在socket大于1024时。文件描写叙述符自然就大于1024,则在使用select时訪问的大小就实际超越了系统中对于select的支持。因此出现读写越界,造成程序的宕机。
这次所踩的坑很隐晦,但也说明了一个问题。在使用系统接口时须要谨慎。尽管可能用法并没有错误,但也要在使用的时候多注意其“潜规则”。
我用select做多路复用踩到的坑的更多相关文章
- gevent协程、select IO多路复用、socketserver模块 改造多用户FTP程序例子
原多线程版FTP程序:http://www.cnblogs.com/linzetong/p/8290378.html 只需要在原来的代码基础上稍作修改: 一.gevent协程版本 1. 导入geven ...
- 用select (多路复用)模拟一个 socket server
需求:用select (多路复用)模拟一个 socket server.可以接收多并发. 1. 一开始是检测自己,如果我有活动了,就说明有客户端要连我了. #用select去模拟socket,实现单线 ...
- wrk 使用记录及踩过的坑
wrk是什么?https://github.com/wg/wrk wrk 是一个非常小巧高效的开源性能测试工具,支持lua脚本来创建复杂的测试场景.wrk 的一个很好的特性就是能用很少的线程压出很大的 ...
- 【转载】Fragment 全解析(1):那些年踩过的坑
http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...
- 使用ffmpeg视频编码过程中踩的一个坑
今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果: ...
- 《C++之那些年踩过的坑(二)》
C++之那些年踩过的坑(二) 作者:刘俊延(Alinshans) 本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑.以此作为给自己的警惕. 今天讲一个小点,虽然小,但如果没有 ...
- 《C++之那些年踩过的坑(三)》
C++之那些年踩过的坑(三) 作者:刘俊延(Alinshans) 本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑.以此作为给自己的警惕. [版权声明]转载请注明原文来自:h ...
- 《C++之那些年踩过的坑(附录一)》
C++之那些年踩过的坑(附录一) 作者:刘俊延(Alinshans) 本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑.以此作为给自己的警惕. [版权声明]转载请注明原文来自 ...
- CentOS7.2上用KVM安装虚拟机window10踩过的坑
最近两个星期一直在琢磨kvm安装window10操作系统,并且通过桥接模式与外界通信,经历了九九八十一难,终于搞定.下面就记录以下我们在探索的过程中踩过的坑. 安装KVM 1. 系统要求:需要一台可以 ...
随机推荐
- aspx页面直接访问后台方法
在方法上面机上[WebMethod]就可以直接请求该方法了.
- nyoj 题目6 喷水装置
喷水装置(一) 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 现有一块草坪,长为20米,宽为2米,要在横中心线上放置半径为Ri的喷水装置,每个喷水装置的效果都会让以 ...
- 山贼集团 (group)
山贼集团 (group) 题目描述 某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两个小村落有且仅有一条简单路径相连.小村落用阿拉伯数字编号为1,2,3,4,-,n ...
- codevs1690 开关灯
1690 开关灯 USACO 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description YYX家门前的街上有N( ...
- wordpress install 主题
手动安装,你可到访WordPress官方网站的主题部分,找到你喜欢的主题后,可压缩下载到电脑并将其解压缩: 上传.zip 包到服务器,解压到 wordpress/wp-content/themes c ...
- APK包与类更改分析
360APK包与类更改分析 1 题目要求 这是360的全球招募无线攻防中的第二题,题目要求如下: 1)请以重打包的形式将qihootest2.apk的程序包名改为 "com.qihoo.cr ...
- input输入框与元素间有间隙
<div class="container"> <button>1</button> <button>2</button> ...
- 网页制作教程:td也可以溢出隐藏显示【转】
原文发布时间为:2010-02-05 -- 来源于本人的百度文章 [由搬家工具导入] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Stri ...
- 用email实现邮件模板
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Python连接MySQL数据库操作
一.创建数据库及表 CREATE DATABASE testdb; USE testdb; CREATE TABLE `tb_user` ( `id` INT (11) NOT NULL AUTO_I ...