`
pengpeng
  • 浏览: 82003 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

[原]客户/服务器程序设计范式

阅读更多

 

                           本篇从基于TCP/IP协议出发,探讨现代流行的应对高并发请求网络服务端设计架构;

1. TCP/IP 模型

首先回顾一下TCP/IP模型,并知道各个层次在操作系统的哪一个层次; 

   看上图,OSI模型的底下两层是随系统提供的设备驱动程序和网络硬件。通常情况下,除需知道数据链路的某些特性外,我们不用关心这两层的情况。网络层由IPv4和IPv6两个协议处理,可以选择的传输层有TCP或UDP。OSI模型的顶上三层被合并为一层,称为应用层,这就是web客户(浏览器)、telnet客户、web服务器等都所在的层。

   可见OSI模型以传输层为分界线;套接字编程接口为应用层进入传输层的接口;也符合抽象的目的:对应用层隐藏网络协议的具体通信细节,应用层只处理具体网络应用;而底下四层(从传输层到物理层)对具体网络应用了解不多,却处理所有的通信细节:发送数据,等待确认,给无序到达的数据排序,计算并验证校验和,等等。

   其次,顶上三层通常构成所谓的用户进程,底下四层却通常作为操作系统内核的一部分提供。完全符合Unix和其他现代操作系统都提供分割用户进程和内核的机制。

2. 基本TCP 套接字编程

   TCP:传输控制协议(Transmission Control Protocol).TCP是一个面向连接的协议,为用户进程提供可靠的全双工字节流。TCP套接字是一种流套接字(stream socket). TCP关心确认,超时和重传之类的细节。大多数网络应用程序使用TCP;

    以apache为例子;apache工作在OSI模型的应用层;我们都知道启动apache后他会监听在80端口,并通过线程池来响应每个客户请求;即来一个客户请求,从连接池那出一个线程去处理这个请求;那么apache的内部是如何针对每个请求创建套接字,然后分配一个线程的呢?

    看图2,apache服务器启动后通过创建监听套接字listensocket,通过调用bind(),listen(),accept(),让主线程监听在80端口;客户请求过来后tcp三次握手,握手成功后accept()返回一个已连接套接字connsocket,代表与所返回客户的tcp连接;然后apache从连接池里拉出一个线程,并将这个已连接套接字给这个线程,让次线程处理这个请求;请求处理完毕后关闭连接,已连接套接字相应的回收;

注:监听套接字(listening socket)是在该tcp服务进程生命周期内一直存在。而已连接套接字代表一个和客户请求建立的一个套接字,生命周期为一次请求;



 

                     图2 : 基本TCP客户/服务器程序套接字函数

注:我们的jms客户端程序也是采用主线程监听队列消息,并将收到的消息给线程池里的一个线程去处理的方式来并发处理消息;

3. 现代并发web服务器的设计范式:

     但是apache真的是一个主线程在监听80端口么? 不是的,一个主线程监听80端口,然后将已连接套接字抛给线程池里的线程去处理,有些缺点;

     缺点如下:1. 只有一个线程监听80端口,并负责三次握手和转发已连接套接字;万一此线程挂了,整个web server就没有服务能力了,容错能力不强;

                    2. 因为connect(),accept()都是阻塞函数。所以每个客户请求来都阻塞在主线程,导致不能很好的应对并发;

     基于这些缺点;apache采用每个线程都去监听80端口,当然同一时刻,只有一个线程在监听80端口;其他线程属于空闲状态;一个客户请求过来,正在监听的线程会处理这个请求并转换为工作者线程;并让出监听者的角色,这样其他线程竞争监听者的角色,并最终有一个线程监听80端口;当一个工作线程处理完请求后,回到连接池中,又处于空闲状态;

但是这样又有问题,如果一个客户请求过来,会导致所有的空闲线程都去竞争监听者的角色。会导致很多空闲线程一下被唤醒,并只有一个线程获得监听者角色,其他线程继续空闲(睡觉),这种大批线程从空闲状态突然被唤醒有突然又睡过去,就是惊群现象;惊群现象会导致性能下降;

     apache通过在每个accept()函数上  增加互斥锁和条件变量   来解决这个惊群问题。保证每个请求只会被一个线程刚好拿到,不会影响其他线程;

       这里详细介绍下: 条件变量与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用;互斥锁提供互斥机制,条件变量提供信号机制;
     那么apache是如何利用条件变量和互斥锁来解决每次只有一个空闲线程被唤醒,并且处于监听者角色呢?
     每次一个新的客户请求过来,正在监听的线程与该请求建立连接,并变为worker工作者线程。让出监听者角色时它同时发送信号到条件变量,并释放锁。这样在空闲(idle)状态的一个线程将被唤醒并获得锁。

     也就是说:条件变量保证了其他线程在等待条件变化期间处于睡眠;互斥锁保证一次只有一个线程被唤醒;


                                                      图3 :apache 的preforking 机制

 

 

总结:通过了解了TCP/IP编程模型。和apache的MPM、Preforking机制后,我们再去看jms消息客户端代码,memcache服务器代码,jetty,等流行的web服务器的机制就不是很难了。

                                                                                                                                                       参考:《UNIX网络编程 卷1 :套接字联网API》

分享到:
评论

相关推荐

    UNIX网络编程 第2卷 进程间通信.pdf(带书签)

    UNIX网络编程 第2卷 进程间通信 第1部分 简介和TCP/IP? 第1章 简介 第2章 传输层:TCP、UDP和SCTP 第2部 分基本套接口编程? 第3章 套接口编程简介 ...第30章 客户/服务器程序设计范式 第31章 流 第4部分 附录?

    UNIX网络编程卷1:套接字联网API(第3版)part1 共2部分

    第一部分 简介和TCP/IP 第1章 简介 ... 第30章 客户/服务器程序设计范式 第31章 流 附录A IPv4、IPv6、ICMPv4和ICMPv6 附录B 虚拟网络 附录C 调试技术 附录D 杂凑的源代码 附录E 精选习题答案 参考文献 索引

    UNIX网络编程 卷1:套接字联网API

    第一部分 简介和TCP/IP ...第30章 客户/服务器程序设计范式 第31章 流 附录A IPv4、IPv6、ICMPv4和ICMPv6 附录B 虚拟网络 附录C 调试技术 附录D 杂凑的源代码 附录E 精选习题答案 参考文献 索引

    UNIX网络编程卷2进程间通信(第2版)

    进程间通信(IPC)几乎是所有Unix程序性能的关键,理解IPC也是理解如何开发不同主机间网络应用程序的必要条件。本书从对Posix IPC和System V IPC的内部结构...第30章 客户/服务器程序设计范式 第31章 流 第4部分 附录?

    搜狗公司C++服务器引擎,编程范式 支撑搜狗几乎所有后端C++在线服务,包括所有搜索服务,云输入法,在线广告等

    搜狗公司C++服务器引擎,编程范式。支撑搜狗几乎所有后端C++在线服务,包括所有搜索服务,云输入法,在线广告等,每日处理数百亿请求。这是一个设计轻盈优雅的企业级程序引擎,可以满足大多数后端与嵌入式开发需求。

    完整版《HTML5高级程序设计》2

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 添加...

    HTML5程序设计(第2版).[荷]Peter Lubbers(带详细书签).pdf

    《深入HTML5编程(第 2版)》首先介绍了HTML5的历史背景、新的语义标签及与以往HTML版本相比的根本变化,同时揭示了HTML5背后的设计原理。本书在上一版的基础上新增了SVG和拖放API相关内容,并对部分内容进行了更新。...

    完整版《HTML5高级程序设计》4

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 添加...

    这是一个设计轻盈优雅的企业级C++服务器引擎

    C++服务器引擎,编程范式。支撑搜狗几乎所有后端C++在线服务,包括所有搜索服务,云输入法,在线广告等,每日处理数百亿请求。这是一个设计轻盈优雅的企业级程序引擎,可以满足大多数后端与嵌入式开发需求

    HTML5高级程序设计

    本书首先介绍了html5 的历史背景、新的语义标签及与以往html 版本相比的根本变化,同时揭示了html5 背后的设计原理。从第2 章起,分别围绕构建令人神往的富web 应用,逐一讨论了html5 的canvas、geolocation 、...

    HTML5高级程序设计.part5

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 ...

    ICE讲座资料,包括PPT和C++源程序

    在这里我们要讲的可不是冰激淋,而是一种用于分布式程序设计的网络通信中间件ICE(Internate Communications Engine).ICE的设计目标主要是以下几点: • 提供适用于异种环境的面向对象中间件平台。 在用ICE进行分布式...

    HTML5高级程序设计.part4

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 ...

    HTML5高级程序设计.part1

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 ...

    HTML5高级程序设计.part2

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 ...

    HTML5高级程序设计.part3

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 ...

    完整版《HTML5高级程序设计》5

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 添加...

    完整版《HTML5高级程序设计》3

    6.3 编写简单的Echo WebSocket服务器 120 6.4 使用HTML5 WebSockets API 126 6.4.1 浏览器支持情况检测 126 6.4.2 API的基本用法 127 6.5 创建HTML5 WebSockets应用程序 130 6.5.1 编写HTML文件 131 6.5.2 添加...

Global site tag (gtag.js) - Google Analytics