设为首页 加入收藏

TOP

6.6.2 常见的并发网络服务程序设计方案(1)
2013-10-07 16:03:50 来源: 作者: 【 】 浏览:72
Tags:6.6.2 常见 并发 网络服务 程序设计 方案

6.6.2 常见的并发网络服务程序设计方案(1)

W. Richard Stevens 的《UNIX 网络编程(www.cppentry.com)(第2 版)》第27 章“Client-ServerDesign Alternatives”介绍了十来种当时(20 世纪90 年代末)流行的编写并发网络程序的方案。[UNP] 第3 版第30 章,内容未变,还是这几种。以下简称UNP CSDA方案。[UNP] 这本书主要讲解阻塞式网络编程(www.cppentry.com),在非阻塞方面着墨不多,仅有一章。正确使用non-blocking IO 需要考虑的问题很多,不适宜直接调用Sockets API,而需要一个功能完善的网络库支撑。

随着2000 年前后第一次互联网浪潮的兴起,业界对高并发HTTP 服务器的强烈需求大大推动了这一领域的研究,目前高性能httpd 普遍采用的是单线程Reactor方式。另外一个说法是IBM Lotus 使用TCP 长连接协议,而把Lotus 服务端移植到Linux 的过程中IBM 的工程师们大大提高了Linux 内核在处理并发连接方面的可伸缩性,因为一个公司可能有上万人同时上线,连接到同一台跑着Lotus Server 的Linux 服务器。

可伸缩网络编程(www.cppentry.com)这个领域其实近十年来没什么新东西,POSA2 已经进行了相当全面的总结,另外以下几篇文章也值得参考。

http://bulk.fefe.de/scalable-networking.pdf

http://www.kegel.com/c10k.html

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

表6-1 是笔者总结的12 种常见方案。其中“互通”指的是如果开发chat 服务,多个客户连接之间是否能方便地交换数据(chat 也是附录A 中举的三大TCP 网络编程(www.cppentry.com)案例之一)。对于echo/httpd/Sudoku 这类“连接相互独立”的服务程序,这个功能无足轻重,但是对于chat 类服务却至关重要。“顺序性”指的是在httpd/Sudoku这类请求响应服务中,如果客户连接顺序发送多个请求,那么计算得到的多个响应是否按相同的顺序发还给客户(这里指的是在自然条件下,不含刻意同步)。

 

UNP CSDA 方案归入0  5。方案5 也是目前用得很多的单线程Reactor 方案,muduo 对此提供了很好的支持。方案6 和方案7 其实不是实用的方案,只是作为过渡品。方案8 和方案9 是本文重点介绍的方案,其实这两个方案已经在§3.3 “多线程服务器的常用编程(www.cppentry.com)模型”中提到过,只不过当时没有用具体的代码示例来说明。

在对比各方案之前,我们先看看基本的micro benchmark 数据(前两项由Thread_bench.cc 测得,第三项由BlockingQueue_bench.cc 测得,硬件为E5320,内核Linux 2.6.32):

fork()+exit(): 534.7μs。

pthread_create()+pthread_join(): 42.5μs,其中创建线程用了26.1μs。

push/pop a blocking queue : 11.5μs。

Sudoku resolve: 100us (根据题目难度不同,浮动范围20200μs)。

方案0 这其实不是并发服务器,而是iterative 服务器,因为它一次只能服务一个客户。代码见[UNP] 中的Figure 1.9,[UNP] 以此为对比其他方案的基准点。这个方案不适合长连接,倒是很适合daytime 这种write-only 短连接服务。以下Python代码展示用方案0 实现echo server 的大致做法(本章的Python 代码均没有考虑错误处理):

  1. recipes/python/echo-iterative.py  
  2. 3 import socket  
  3. 4  
  4. 5 def handle(client_socket, client_address):  
  5. 6 while True:  
  6. data = client_socket.recv(4096)  
  7. 8 if data:  
  8. sent = client_socket.send(data) # sendall  
  9. 10 else:  
  10. 11 print "disconnect", client_address  
  11. 12 client_socket.close()  
  12. 13 break  
  13. 14  
  14. 15 if __name__ == "__main__":  
  15. 16 listen_address = ("0.0.0.0", 2007)  
  16. 17 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
  17. 18 server_socket.bind(listen_address)  
  18. 19 server_socket.listen(5)  
  19. 20  
  20. 21 while True:  
  21. 22 (client_socket, client_address) = server_socket.accept()  
  22. 23 print "got connection from", client_address  
  23. 24 handle(client_socket, client_address)  
  24. recipes/python/echo-iterative.py 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇6.6.1 数独求解服务器 下一篇6.6.2 常见的并发网络服务程序设..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·用 C 语言或者限制使 (2025-12-25 08:50:05)
·C++构造shared_ptr为 (2025-12-25 08:50:01)
·既然引用计数在做 GC (2025-12-25 08:49:59)
·Java 编程和 c 语言 (2025-12-25 08:19:48)
·. net内存管理宝典这 (2025-12-25 08:19:46)