- 网络程序中,数据通讯的时间比CPU运行时间长,因此服务器需要同时向多个客户提供服务,这样可以有效利用CPU
- 并发服务器的实现方案
- 多线程(多进程)服务器
- 多路复用服务器
- 进程定义了一个计算的基本单元,是操作系统中单独执行流的单位,可以认为是一个程序的一次运行。
- 进程拥有独立的地址空间、执行堆栈、文件描述符等
- 进程之间互不影响,一个进程的崩溃不会造成其他进程的崩溃。
- 当进程间共享某一资源时,需注意两个问题:同步问题和通信问题。
- 多进程通信模型的缺点
- 创建、切换开销较大
- 数据交换较为复杂
- 线程是进程内的独立执行实体和调度单元,是进程中单独执行的流的单位
- 又称为“轻量级”进程(lightwight process)
- 创建线程比进程快10~100倍
- 一个进程内的所有线程共享相同的内存空间、全局变量等信息
- 线程模型的优点
- 创建、切换开销较小
- 数据交换简单(共享数据空间)
- 创建线程
- CreateThread()
- _beginthreadex()
- 关闭线程
- ExitThread()
- _endthreadex()
- 线程最后执行Return
语法
uintptr_t _beginthreadex
( void *security, // 安全属性, 为NULL时表示默认安全性
unsigned stack_size, // 线程的堆栈大小, 一般默认为0
unsigned (*start_address )( void * ), // 所要启动的线程函数
void *arglist, //传递给线程的参数指针,在线程函数中再转化为对应类的指针
unsigned initflag, // 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED
unsigned *thrdaddr // 用来接收线程ID
);
返回值 : // 成功返回新线程句柄, 失败返回0
多线程/多进程服务器的缺点
- 为了构建并发服务器,只要有客户端连接请求,就会创建新的进程/线程,创建时需要消耗一定的代价(内存空间、CPU时间等)
-
基于I/O复用——仅使用一个进程/线程
-
什么是“复用”,网络并行通讯怎么复用?
-
客户端和服务端通过文件描述符(Socket函数创建)来完成数据发生和接受
-
基于socket的通讯(以TCP服务器为例)
- TCP服务器通过accept函数,为每个请求连接的新客户创建一个文件描述符
如何让该服务器同时处理多个文件描述符,即同时服务多个客户,同时对这些客户发送和接收消息?
下面分别介绍
- 文件描述符
- 记录多个文件描述符的数据结构fd_set
- 监视文件描述符的函数select
- 操作系统内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
- 它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。
- 标识每个端口的两个值(IP地址和端口号)通常称为一个套接字。
- 套接字是一个抽象出来的概念,本质上也是一个文件描述符。
- 通常使用fd_set数组来记录多个文件描述符
- 使用Select函数可以集中监测多个文件描述符,即监视多个套接字
- 是否存在套接字接收数据
- 是否有套接字发生数据
- 哪些套接字发生了异常
- Select函数的使用方法和一般函数区别较大
- 步骤1
- 设置文件描述符
- 指定监视范围
- 设置超时
- 步骤2
- 调用Select函数
- 步骤3
- 查看调用结果
- 将需要监视的文件描述符集中在一起,集中时按照“接收、发送、异常”分类
- 使用fd_set数组来设置文件描述符
- fd(x)表示数组的第x+1个元素,x等于文件描述符的数值
- 方框里的值表示数组的值,如果某位为1,则表示所对应的文件描述符是被监视的对象
- 图中表示文件描述符为2和4的是被监视的对象
- 置位 操作通过FD_SET函数完成
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
- 通过maxfds指定监视范围
- 通过设置select函数的三个参数readfds、 writefds、exceptfds来指定监视对象
- 将被监视的文件描述符对应的fd_set位置1
- select函数只有在被监视的文件描述符发生变化时才返回;如果没有发生变化则进入阻塞状态。
- 指定参数timeout后,即使文件描述符没有发生变化,只要过了指定时间,也可以从select函数中返回,此时返回0。
- 如果不想设置超时,那么传递NULL。
怎样获知哪些文件描述符发生了变化?
- Select函数调用前通过置1来指定被监视的文件描述符;
- select函数调用后,其fd_set将发生变化——原先被监视的文件描述符如果发生变化,那么对应的fd_set保持为1;如果没发生变化,那么变为0。
-
Select函数返回正整数时,该值表示发生变化的文件描述符数目
- readfds 接收
- writefds 发送
- exceptfds 异常
-
怎样获知变化:看fd_set数组(上述三个)的各个元素的变化情况



