Linux网络编程--(5)Linux常见服务器模型

来源:互联网 发布:简述对大数据的理解 编辑:程序博客网 时间:2024/06/07 00:47

一、循环服务器

一个服务器同一时刻只能响应一个客户端的请求。

(1)TCP循环服务器

服务器运行后等待客户端的连接请求

服务器接受一个客户端的连接后开始处理,完成客户的所有请求后断开连接

循环服务器一次只能处理一个客户端的请求

只有在当前客户的所有请求都完成后,服务器才能处理下一个客户的连接/服务请求

如果某个客户端一直占用服务器资源,那么其他的客户端不能被处理,TCP服务器一般很少采用循环服务器。

TCP循环服务器的流程如下:

socket();

bind();

listen();

while(1){

accept();

while(1){

recv();

process();

send();

}

close();

}

(2)UDP循环服务器

UDP服务器每次从套接字读入一个客户端的请求,处理后将结果返回给客户机

UDP循环服务器的例程如下:

socket();

bind();

while(1){

recvform();

process();

sendto();

}

close();

二、并发服务器

(1)TCP并发服务器

为了弥补TCP循环服务器的缺陷,并发服务器的设计思想是服务器接收客户端的连接请求后,创建子进程来为客户端服务

避免了循环服务器中客户端独占服务器的情况

为了响应客户端的请求,服务器创建子进程来处理。如果多个客户端连接,就创建多个子进程,过多的子进程会影响客户端的运行效率。

TCP并发服务器的流程如下:

socket();

bind();

listen();

while(1){

accept();

if(fork()==0){

while(1){

recv();

process();

send();

}

close();

exit(0);

}

close();

(2)UDP并发服务器

人们把并发概念用到UDP上,就得到了UDP并发服务器模型

与TCP相同,它也是创建一个子进程来处理客户端的请求。

除非UDP服务器在处理某个客户端的请求时所用的时间较长,人们实际上较少用这种模型

三、IO模型

(1)阻塞IO

最常用、最简单、效率最低

阻塞IO是最普遍使用的IO模型,大部分程序使用的都是阻塞模式IO,缺省情况下,套接字建立后所处于的模式就是阻塞IO模式。

read、recv、recvfrom、write、send、accept、connect函数在调用是都会发生阻塞

(2)非阻塞IO

可防止进程阻塞在IO操作上,需要轮询。

将套接字设置为非阻塞模式,就相当于告诉系统内核:我请求的IO操作不能马上完成时,直接返回给一个错误给我。别进入休眠状态。当一个应用程序使用了非阻塞模式,它需要使用一个循环来不停的测试是否一个文件描述符有数据可读(polling)。应用程序不停的polling内核来检查是否IO操作已经就绪。这将是一个及其浪费CUP资源的操作。因此此模式的使用不普遍。


(3)多路复用IO

允许同时对多个IO进行控制

应用程序中同时处理多路输入输出流,如果采用阻塞模式,就无法达到目的。采用非阻塞模式需要轮询,又很浪费CPU。如果设置多个进程来分别处理一条数据通路,将新产生进程间的通信问题,是得程序极其复杂。

于是IO多路复用出现,其思想为:

先构造一张有关描述符的表,然后调用一个函数。当这些文件描述符中的一个或者多个已经准备好进行IO时,函数返回。

函数返回时,告诉进程那个描述符已经就绪,可以进行IO操作。描述这张表的函数就是select函数

select函数:

#include <sys/select.h>

#include <sys/time.h>

#include <sys/types.h>

#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

功能

阻塞,当他维护的文件描述符集合中的任意一个描述符有数据发生变化,,就会立刻返回.然后去判断集合中哪个文件描述符发生了变化

参数

int nfds  维护的文件描述符中最大的值+1

fd_set *readfds   读集合

fd_set *writefds  集合

fd_set *exceptfds

struct timeval *timeoutNULL 一直阻塞=0     非阻塞>0     超时时间

struct timeval {

long    tv_sec;         /* seconds */

long    tv_usec;        /* microseconds */

 };

void FD_CLR(int fd, fd_set *set);  从set中删除fd

int  FD_ISSET(int fd, fd_set *set); 判断fd是否发生了变化

void FD_SET(int fd, fd_set *set);  将fd加入到set这个集合中

void FD_ZERO(fd_set *set);         清空

四、多路复用IO 的模型框图

五多线程并发服务器的模型框图