C10K问题
 
网络服务在处理数以万计的客户端连接时,往往出现效率底下甚至完全瘫痪,这被成为C10K问题。
(C10K = connection 10 kilo 问题)。k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克)。
 
非阻塞I/O,最关键的部分是readiness notification(when ready, then notify!)和找出哪一个socket上面发生了I/O事件。
一般我们首先会想到用select来实现。
int select(int n, fd_set *rd_fds; fd_set *wr_fds, fd_set *ex_fds, struct timeval * timeout);
 
其中用到了fd_set结构,而fd_set不能大于FD_SETSIZE,默认是1024,很容易导致数组越界。
针对fd_set的问题,*nix提供了poll函数作为select的一个替代品:
int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
第一个参数ufds是用户提供的一个pollfd数组,大小由用户自行决定,因此避免了FD_SETSIZE带来的麻烦。
然而select和poll在连接数增加时,性能急剧下降。这有两方面的原因:
 
  《1》首先操作系统面对每次的select/poll操作,都需要重新建立一个当前线程的关心事件链表,并把线程挂在这个复杂的等待队列上,这是相当耗时的。
  《2》其次,应用软件在select/poll返回后也需要对传入的句柄链表做一次循环扫描来dispatch,这也是很耗时的。这两件事都是和并发数相关,而I/O事件的密度也和并发数相关,导致CPU占用率和并发数近似成O(n2)的关系。
 
基于以上原因,*nix的hacker们开发了epoll, kqueue, /dev/poll这3套利器。epoll是Linux的方案,kqueue是freebsd的方案,/dev/poll是solaris的方案。
简单的说,这些api做了两件事:
 
  《1》避免了每次调用select/poll时kernel分析参素建立事件等结构的开销,kernel维护一个长期的时间关注列表,应用程序通过句柄修改这个链表和捕获I/P事件
  《2》避免了select/poll返回后,应用程序扫描整个句柄表的开销,kernel直接返回具体的链表给应用程序。
 
在接触具体api之前,先了解一下边缘触发(edge trigger)和条件触发(level trigger)的概念。边缘触发是指每当状态变化时发生一个io事件,假定经过长时间的沉默后,现在来了100个字节,这是无论边缘触发和条件触发都会产生一个read
ready notification通知应用程序可读。应用程序在读完来的50个字节,然后重新调用api等待io事件。这时条件触发的api会因为还有50个字节可读从而立即返回用户一个read ready notification。而边缘触发的api会因为可读这个状态没有发生变化而陷入长期等待。
因此在使用边缘触发的api时,要注意每次都要读到socket返回EWOULDBLOCK为止,
否则这个socket就算废了。而使用条件触发的api时,如果应用程序不需要写就不要关注socket可写的事件,否则会无限次的立即返回一个
write ready nitification.
大家常用的select就是属于条件触发这一类,以前本人翻过长期关注socket写事件从而CPU
100%的毛病。
 
epoll相关调用:
int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
 
epoll_create 创建kernel中的关注事件表,相当于创建fd_set.
epoll_ctl 修改这个表,相当与FD_SET等操作。
epoll_wait 完全是select/poll的升级版,支持的事件完全一致。并且epoll同时支持边缘触发和条件触发,一般来讲边缘触发的性能要好一些。
 
简单的例子:
[cpp] view plaincopy

        strut epoll_event ev, *events;
int kdpfd = epoll_create(); //创建kernel中的关注事件表,返回一个kernel事件表的句柄 ev.events = EPOLLIN | EPOLLET; //边缘触发
ev.data.fd = listener;
epoll_ctl(kdpfd, EPOLL_CTL_ADD, listener, &ev); //将事件ev加入到kernel关注的事件表中 for(;;){ nfds = epoll_wait(kdpfd, events, maxevents, -); //等待被通知
for(n = ; n < nfds; n++){
if(events[n].data.fd == listener){
client = accept(listener, (struct sockaddr*)&local, &addrlen);
if(client < ){
peror("accept");
continue;
} setnonblocking(client);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = client;
if(epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < ){
fprintf(stderr, "epoll set insertion error: fd = %d, client);
return -;
}
}else
do_use_fd(events[n].data.fd);
}
}

网络编程——C10K简述的更多相关文章

  1. 网络编程——The C10K Problem(C10K = connection 10 kilo 问题)。k 表示 kilo,即 1000

    The C10K problem翻译 (C10K = connection 10 kilo 问题).k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克). 如 ...

  2. python网络编程01 /C/S架构|B/S架构、网络通信原理、五层协议、七层协议简述、端口映射技术

    python网络编程01 /C/S架构|B/S架构.网络通信原理.五层协议.七层协议简述.端口映射技术 目录 python网络编程01 /C/S架构|B/S架构.网络通信原理.五层协议.七层协议简述. ...

  3. 简述TCP网络编程本质

    基于事件的非阻塞网络编程是编写高性能并发网络服务程序的主流模式,头一次使用这种模式编程需要转换思维模式 .把原来的"主动调用recv()来接收数据,主动调用accept()来接受连接,主动调 ...

  4. 1、简述在java网络编程中,服务端程序与客户端程序的具体开发步骤?

    网络编程分为UDP通信和TCP通信 UDP协议: 发送端:1.创建DatagramSocket对象.2.创建DatagramPacket对象,并封装数据.3.发送数据.4.释放 资源. 接收端:1.创 ...

  5. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  6. 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

    .引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...

  7. 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

    本文原作者:“水晶虾饺”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.引言 好多小白初次接触即时通讯(比如:IM或者消息推送应用)时,总是不 ...

  8. 网络编程懒人入门(六):深入浅出,全面理解HTTP协议

    本文引用了自简书作者“涤生_Woo”的文章,内容有删减,感谢原作者的分享. 1.前言 HTTP(全称超文本传输协议,英文全称HyperText Transfer Protocol)是互联网上应用最为广 ...

  9. [转帖]脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?     http://www.52im.net/thread-1732-1-1.html   1.引言 本文接上篇<脑残式网 ...

随机推荐

  1. 转载---sql之left join、right join、inner join的区别

    原文地址:http://www.cnblogs.com/pcjim/articles/799302.html sql之left join.right join.inner join的区别 left j ...

  2. 使用rosbag记录openni2_launch消息

    首先看教程 http://wiki.ros.org/openni_launch/Tutorials/BagRecordingPlayback http://wiki.ros.org/Bags http ...

  3. 好的web前端是如何拿到30万年薪的?

    2018年前端开发不再像过去几年里新技术框架层出不穷,而是各种组件,模块,很多东西都有痕迹可寻,技术都在原来的基础上有了革新和沉淀. 前端招聘方面也在紧跟技术发展,大量“滥竽充数”的速成开发者开始失去 ...

  4. [php] 解析JSON字符串

    $json_str = '{"thumb":"","photo":[{"url":"557a3d2184db0 ...

  5. 洛谷 P1068 分数线划定【结构体排序】

    题目描述 世博会志愿者的选拔工作正在 A 市如火如荼的进行.为了选拔最合适的人才,A 市对 所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试.面试分数线根 据计划录取人数的150%划 ...

  6. [BZOJ4316]小C的独立集(圆方树DP)

    题意:求仙人掌图直径. 算法:建出仙人掌圆方树,对于圆点直接做普通的树上DP(忽略方点儿子),方点做环上DP并将值直接赋给父亲. 建图时有一个很好的性质,就是一个方点在邻接表里的点的顺序正好就是从环的 ...

  7. jvm-监控指令-jstat

    格式: jstat -<option> <vmid> [<interval> [<count>]] 作用: 查看虚拟机各种运行状态信息.         ...

  8. node.js学习一——什么是node.js

    定义:node.js是运行在服务器端的运用了谷歌v8引擎的javascript运行平台 特点:1. 异步式I/O(非阻塞式I/O) 2. 事件驱动 什么是异步式I/O(非阻塞式I/O)? 要了解什么是 ...

  9. Easyui treegrid 无法显示树形结构解决办法

    easyui treegrid 中检查了数据结构没有问题的,但就是不展示树形结构, 检查发现原来是 var columnsAll = [ { title: '任务ID', field: 'TaskID ...

  10. DataRow 数组转化成DataTable

    #region 封装DataTable DataTable dt = null; if (newRows.Length > 0) { dt = newRows[0].Table.Clone(); ...