您的位置:首页 > 理论基础 > 计算机网络

网络编程资源

2014-04-18 22:56 68 查看

高性能 Socket 组件 HP-Socket v3.2.1-RC1 发布

http://bbs.csdn.net/topics/390763397

The C10K problem 高性能服务器设计
http://www.cnblogs.com/fll/archive/2008/05/17/1201540.html http://blog.sina.com.cn/s/blog_4aec22920100itkf.html
这周看了Dan Kegel那篇"The C10K problem",以下和大家分享一下。

故名思义,这文章是分析如果编写一个服务器程序来支持上万的客户端连接的。

其关注的重点是io效率,目前大规模网络程序的关键瓶颈。

作者认为需要权衡利弊的要点有以下

1.单线/进程处理多个I/O的做法: 其可选的方案有

a. 不这样做。
也就是对单线程使用阻塞同步的IO(意为依靠多线/进程来处理多个IO)。

b. 使用非阻塞IO。
即以非阻塞方式启动IO,并等待IO就绪通知(select / poll等,通常对网络IO有效,但不能提高磁盘IO的效率)

c. 使用异步IO。
调用 aio_write启动IO,并等待IO的完成通知。

2.如果管理client连接

a.
一个进程处理一个client (经典unix方式)

b.
一个OS-level线程处理多个client,
对应每个client使用一个user-level线程(即线程库,虚拟机提供的线程,协同等方式)

c.
一个OS-level线程处理一个client (java的内置线程等)

d.
一个OS-level线程处理一个活跃的client

3. 是否使用标准OS服务,还是把依靠具体OS内核

以上的选择互相组合,产生一些常见解决方案.

1. 单线程处理多client,使用非阻塞IO 和水平触发的就绪通知

**水平触发(level-trigger)与边界触发(edge-trigger)对应,简要说水平触发意为根据状态

也判断是否触发某事件, 而边界触发根据变化来判断是否触发某事件。

也就是传统的io多路复用,这是目前大部分网络程序的解决方式,它可以方便的在一个线程里管理多个

io。不需要考虑多线/程等问题, 代码的逻辑不需要加入额外的复杂性。

但这里所指的非阻塞,是指在某个fd未就绪时的read或write操作, 程序不等待它的就绪而已。

这边存在上面说对于磁盘IO并没有提高效率的问题。

在大规模地对磁盘读写操作时, read 或write还是会导致整个程序长时间阻塞。

如果要避免这种情况,必须引入异步IO。 对于部分缺乏AIO的系统,就只能建立子线/进程来完成该操作。

另外一种对磁盘IO的优化方式是使用 内存映像IO。

这种方式的关键是判断一组非阻塞的socket何时处于就绪状态。

实现它们的方法有 select, poll, dev/poll 等。

2. 单线程处理多client,使用非阻塞IO 和就绪变化通知

意为使用边界触发的就绪通知。其实这种方案只是1的加速方式, 即只在fd状况发生变化时

才去检查fd是否变为就绪。这种实现必须去处理假事件,因为有些实现方式是fd接到任何包的时候都假定其变为就绪了。

实现它们的有 kqueue, epoll(指定ET模式)等。

一些通用的库如libevent ACE等,把这些底层不同实现封装起来,并提供不同IO策略的选择。 按照

libevent作者Niels的测试数据 kqueue在所有之中性能最高。

3. 多个线程处理多个client, 使用异步IO

这是对于网络IO和磁盘IO都很高效的方式。通常当异步IO发起后, 它使用边界触发的方式来提供IO的完成通知。

然后把完成的通知放到消息队列里,等待程序的后续相应。

但这需要os提供AIO的支持,并且需要以异步的方式来设计程序,有一定复杂性。

4. 多个线程处理client

这是最简单方式,就是让但进/线程 的read 和 write 直接阻塞。

这个方法的最大缺点是, 需要支付每个进/线程的栈空间,并引入额外的上下文切换的开销。

如果需要上万个client, 建立上万的进/线程目前是不太可能的。

5. 把服务器整合到os内核里

部分系统有这样的尝试,例如Liunx下的 khttpd 就是把web服务器整合到

系统内核里。 但这对我们的游戏参考价值不大。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: