1.TCP 迭代服务器程序
这种方式就是服务器同一时间只处理一个客户端的请求, 这个请求处理完以后才转向下一个客户请求. 当然这样的服务器程序比较少见, 这就像一个公司只能一次处理一个客户, 后面的客户只能等待, 这样的话肯定是不行的, 效率太低 了, 但是要是从进程控制角度来看这种方式是最快的, 因为它没有执行进程控制, 这是相对于后面讲的方式多进程而言的, 啥意思呢, 就是说一个公司里面当你只有一个销售员接待客户的时候, 我对销售员的管理成本就没有了, 当你是多个销售员对应多个客户的时候, 虽然这个时候可以同时接待多个客户, 但是老板对多个销售员的管理成本也要算进去, 上面说的进程控制就是老板对多个销售员的管理.
2.TCP 并发服务器程序, 每个客户一个子进程
这种方式呢, 就是多个进程处理多个连接, 每来一个新的连接, 就立即创建 (fork) 一个新的子进程来处理这个连接, 这种方式的问题是为每个新连接现场 fork 一个子进程比较耗费 CPU 时间, 操作系统在 fork 子进程时要做的事情很多的, 首先需要复制父进程的相关数据结构, 然后在初始化权限, 调度器, 文件系统, 内存这一系列操作, 所以创建一个子进程的开销是很大的, 尤其是现在这个时代, 繁忙的服务器每天的连接数可以达到数以百万计.
举例来说这种方式就像你作为老板, 每接一个项目就创建一个新的子公司, 这个子公司的人员, 桌椅板凳, 各种工具都是新的, 项目完成以后该子公司解散.
3.TCP 预先派生子进程服务器程序
这种方式就是在启动阶段预先创建多个子进程, 当各个客户连接到来时, 子进程就可以马上为他们服务, 而不是说当客户来的时候在创建好子进程为他们服务, 这种方式优点就是没有了父进程 fork 的开销, 缺点就是父进程必须在服务器启动阶段猜测需要预先创建多少子进程, 而且父进程还要实时监控进程池中的进程数, 当这个数字高于某个阈值时, 需要终止多余的进程, 当这个数字低于某个阈值时, 需要创建新进程.
举例来说: 这就像老板预先创建了多个子公司, 当来项目时, 让创建好的子公司接项目就可以 了, 而不是像第二种方式那样, 来客户了, 你再去创建子公司, 但是作为老板你要全局把控, 当你发现子公司的数量太多, 已经远大于项目的数量, 这时候你就要注销掉一部分公司, 以节省开销, 同样反过来, 当你发现接的项目数很多, 增长的速度很多, 那么你就需要马上在创建几个子公司来处理项目, 要不然你的项目就接不到了, 就挣不了钱, 无法迎娶白富美, 走上人生巅峰了.
然后我们再说关于这种方式会发生的一个问题, 这个问题就叫做 "惊群", 啥意思呢, 就是说当来了一个新请求时, 所有的进程都会被唤醒, 但是最后只有一个进程能接到这个请求, 这样就会导致性能受损.
举例来说: 当没有项目来的时候, 所有的子公司都处于放假状态, 所有人员都休息了, 然后来了一个新的项目, 所有的公司都得恢复到上班状态, 但是其实到最后只有一个公司能接到这个项目, 这样对于其他子公司员工来说是不是有点烦, 老子正在放假休息呢, 然后你把我召回到了公司还没事情做, 让我白跑一趟, 交通费食宿费这些都属于浪费掉了, 对应到操作系统来说就是性能受损.
4.TCP 并发服务器程序, 每个客户一个线程
这种方式就是每来一个客户请求, 就创建一个线程, 创建线程的开销要比创建进程的开销小多了, 创建线程就是将各个结构的引用计数加一, 创建栈等操作, 相对比创建进程来说开销要小很多了, 这其实就像公司接项目的时候不是创建子公司, 而是创建多个项目组, 项目组可以共用公司的各种资源.
这里说一下 accept 的概念, accept 是套接字 (socket) 中的一个函数, 他是用来接收服务器中已完成连接队列里面的连接, 也就是服务器会有一个队列专门用来存放已经三次握手完成的 tcp 连接, 当这个队列有数据的时候, 调用这个 accept 函数就会从队列头部拿出一个连接给应用程序处理.
5.TCP 预先创建线程服务器程序, 每个线程各自 accept
这种其实就是服务器启动阶段预先创建线程池, 也就是多个线程以取代为每个客户连接现场创建一个线程有性能加速效果, 这种做法就像来了一个新项目, 只有一个项目组接这个项目, 其他项目组还是做原来做的事情.
6.TCP 预先创建线程服务器程序, 主线程统一 accept
这种方式就是在程序启动阶段创建一个线程池之后只让主线程调用 accept 并把每个客户连接传递给池中某个可用线程, 这就像有个所有项目组的总管, 他负责接项目, 来了项目以后, 他去把这个项目分配给可以开发的项目组.
来源: https://www.cnblogs.com/sjks/p/10909563.html