下面有9种服务器模型分别是:

  • 迭代服务器。
  • 并发服务器,为每个客户fork一个进程。
  • 预先派生子进程,每个子进程都调用accept,accept无上锁保护。
  • 预先派生子进程,以文件锁的方式保护accept。
  • 预先派生子进程,以线程互斥锁上锁的方式保护accept。
  • 预先派生子进程,由父进程向子进程传递套接口描述字。
  • 并发服务器,为每个客户请求创建一个线程。
  • 预先创建线程,以互斥锁上锁方式保护accept。
  • 预先创建线程,由主线程调用accept,并把每个客户连接传递给线程池中某个可用线程。

1、迭代服务器

       典型代码:
socket
bind
listen
for(;;)
{
connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
process_connection(connfd);
close(connfd);
}
       优点:主要是编程简单。
       缺点:处理完一个连接之后才能处理下一个连接,无并发可言,应用很少。
2.并发服务器,为每个客户fork一个进程
       典型代码:
init_address(server_addr)
listenfd = socket(AF_INET,SOCKET_STREAM,0);
bind(listenfd, (SA*)server_addr, sizeof(serveraddr));
listen(listenfd,BACKLOG);
for(;;)
{
connfd = accept(listenfd, (SA*)&cliaddr, &clilen);
if(connfd < 0)
{
if(EINTR == errno)
continue;
else
//error
} if(fork() == 0)
{
close(c=listenfd);
process_connection(connfd); //child process
exit(0);
}
close(connfd);//parent, close connected socket
}
       早期的网络服务器每天处理几百或者几千个客户连接时,这种服务器模型还是可以应付的。
       但是随着互联网业务的迅猛发展,繁忙的web服务器每天可能需要处理千万以上的连接,发服务器的问题在于为每个客户现场fork一个子进程比较消耗cpu时间。
3.预先派生子进程,每个子进程都调用accept,accept无上锁保护
     缺点:
  • 服务器必须在启动的时候判断需要预先派生多少子进程
  • 惊群现象(一个连接到来唤醒所有监听进程),不过较新版本的linux貌似修正了这个问题
     优点:无须引入父进程执行fork的开销就能处理新到的客户

4.预先派生子进程,以文件锁的方式保护accept
       本模型与3的区别仅仅是对accept(listenfd)使用了文件锁。
       这种模型是为了解决以库函数的形式实现的accept不能在多个进程中引用同一个监听套接口的问题(源自BSD的unix,在内核中实现的accept可以引用)。使用文件锁保证了每个连接到来,只有一个进程阻塞在accept调用上。对于已经在内核中实现了accept的系统来说,这种模型至少增加了加锁解锁的开销,所以相对于第3种模型性能较低(特别是在消除了惊群问题的系统上)
5.预先派生子进程,以线程互斥锁上锁的方式保护accept
       典型代码:
static pthread_mutex_t *mptr;
void
my_lock_init(char *pathname)
{
int fd;
pthread_mutexattr_t mattr;
//因为是相关进程所以可以使用/dev/zero设备创建共享内存
//优势是调用mmap创建共享存储区之前无需一个实际的文件
//映射/dev/zero自动创建一个指定长度的映射区
fd = open("/dev/zero", O_RDWR, 0,);
// 将mptr映射到共享存储区
mptr = mmap(0, sizeof(pthread_mutex_t), PORT_READ | PORT_WRITE, MAP_SHARED, fd, 0);
close(fd);
pthread_mutexattr_init(&mattr);
pthread_mutexattr_setpshared(&mptr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(mptr, &mattr);
} void
my_lock_wait()
{
pthread_mutex_lock(mptr);
} void
my_lock_release()
{
pthread_mutex_unlock(mptr);
} int
main(int argc, char **argv)
{
//init socket and address
my_lock_init(pathname);
for(i = 0; i < nchildren; ++i)
{
pids[i] = child_make(i, listenfd, addrlen);
} for(;;)
pause();
} pid_t
child_make(int i, int listenfd, int addrlen)
{
pid_t pid; if((pid = fork) > 0)
return pid; child_main(i, listenfd, addrlen);
} void
child_main()
{
for(;;)
{
my_lock_wait();
connfd = accept(listenfd, chiladdr, &clilen);
my_lock_release();
web_child(connfd);
close(connfd);
}
}
       这种模型在模型4上做出了进一步的改进,由于以文件锁的方式实现保护会涉及文件系统,这样可能比较耗时,所以改进的办法是以pthread mutex互斥量代替文件锁。使用线程上锁保护accept不仅适用于同一进程内各线程上锁,也适用于不同进程间上锁在多进程环境下使用线程互斥锁实现同步有两点要求:
1.互斥锁必须放在由所有进程共享的内存区
2.必须告知线程库这是在不同的进程间共享的互斥锁
       注意:目前很火的高性能web服务器的代表nginx就是采用的这种模型,网络上对nginx的研究很多。
6.预先派生子进程,由父进程向子进程传递套接口描述字
     优势:不需要对accept上锁保护
     劣势:
  • 编码复杂—父进程必须跟踪子进程的忙闲状态,以便给空闲子进程传递新的套接口。在前述的预先派生子进程的例子中,父进程无需关心由哪一个子进程接收一个客户连接,操作系统会根据调度算法处理这些细节。采用这种模型的结果是这些进程无法均衡的处理连接。
  • 父进程通过字节流管道把描述子传递到各个子进程,并且各个子进程通过字节流管道写回单个字节,比起无论是使用共享内存区中的互斥锁还是使用文件锁实施的上锁和解锁都更费时。
7.并发服务器,为每个客户请求创建一个线程
       典型代码:
for(;;)
{
connfd = accept(listenfd, cliaddr, &clilen,);
pthread_create(&tid, NULL, &doit, (void *)connfd);
} void *
doit(void *arg)
{
pthread_detach(pthread_self());
web_child((int)arg);
close((int)arg)
return (NULL);
}
       优点:编码简单。
       缺点:现场为每个连接创建线程相对于预先派生线程池来说比较耗时。
8.预先创建线程,以互斥锁上锁方式保护accept
    优势:
  • 编程简介,易于理解
  • 线程池的方式避免了现场创建线程的开销
  • OS线程调度算法保证了线程负载的均衡性
       这就是leader-follower模式一个线程等待连接到来,其他线程休眠;新连接到来后leader去处理连接,释放listenfd,其他线程竞抢监听套接口listenfd(可能有惊群的问题)。leader在处理完连接以后成为follower。
9.预先创建线程,由主线程调用accept,并把每个客户连接传递给线程池中某个可用线程
       劣势:相对于模型8,该模型不仅需要使用pthread mutex额外还需要使用pthread cond。

UNIX网络编程——常用服务器模型总结的更多相关文章

  1. UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数

    UNIX环境高级编程——TCP/IP网络编程   常用网络信息检索函数 gethostname()   getppername()   getsockname()   gethostbyname() ...

  2. UNIX网络编程——并发服务器(TCP)

    在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现. 网络服务器通常用fork来同时 ...

  3. UNIX网络编程——getsockname和getpeername函数

    UNIX网络编程--getsockname和getpeername函数   来源:网络转载   http://www.educity.cn/linux/1241293.html     这两个函数或者 ...

  4. 【LINUX/UNIX网络编程】之简单多线程服务器(多人群聊系统)

    RT,Linux下使用c实现的多线程服务器.这个真是简单的不能再简单的了,有写的不好的地方,还希望大神轻拍.(>﹏<) 本学期Linux.unix网络编程的第四个作业. 先上实验要求: [ ...

  5. 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)

    RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三  多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...

  6. 【Linux/unix网络编程】之使用socket进行TCP编程

    实验一 TCP数据发送与接收 [实验目的] 1.熟练掌握套接字函数的使用方法. 2.应用套接字函数完成基本TCP通讯,实现服务器与客户端的信息交互. [实验学时] 4学时 [实验内容] 实现一个服务器 ...

  7. Unix网络编程--卷二:进程间通信

    Unix网络编程--卷二:进程间通信 本书是一部Unix网络编程的经典之作!进程间通信(IPC)几乎是所有Unix程序性能的关键,理解IPC也是理解如何开发不同主机网络应用程序的必要条件.本书从对Po ...

  8. Unix网络编程--卷一:套接字联网API

    UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...

  9. [转载] 读《UNIX网络编程 卷1:套接字联网API》

    原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/ 文章写的很清楚, 适合初学者 最近看了<UNIX网 ...

随机推荐

  1. hdu 4453 splay

    Looploop Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  2. [Noi2016]优秀的拆分

    来自F allDream的博客,未经允许,请勿转载,谢谢. 如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aab ...

  3. bzoj1069 [SCOI2007]最大土地面积 旋转卡壳

    1069: [SCOI2007]最大土地面积 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 3767  Solved: 1501[Submit][Sta ...

  4. SpringCloud学习之feign

    一.关于feigin feigin是一种模板化,声明式的http客户端,feign可以通过注解绑定到接口上来简化Http请求访问.当然我们也可以在创建Feign对象时定制自定义解码器(xml或者jso ...

  5. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 操作符重载和隐式类型转换

    C#中,某些类型会定义隐式类型转换和操作符重载.Unity中,有些对象也定义了隐式类型转换和操作符重载.典型情况有:UnityEngine.Object.UnityEngine.Object的销毁是调 ...

  6. Android通过聚合数据API实现天气预报

    使用聚合数据的API 聚合数据地址:https://www.juhe.cn/ 在数据服务->生活常用->全国天气预报,申请天气预报的API使用的KEY 保存请求示例的地址,把您申请的KEY ...

  7. 华科机考:a+b

    时间限制:1秒     空间限制:32768K 题目描述 实现一个加法器,使其能够输出a+b的值. 输入描述: 输入包括两个数a和b,其中a和b的位数不超过1000位. 输出描述: 可能有多组测试数据 ...

  8. 阿里 & 酷家乐:实习生面试

    最近海投了十家公司,暂时有阿里两面(已凉).酷家乐两面(大概凉了).网易一面.前两个都是基础知识发挥得还可以,两家公司二面都凉凉. 阿里一面(3.21 26min) 刚好买了中饭回宿舍打开正准备吃的时 ...

  9. jieba库分词统计

    代码在github网站,https://github.com/chaigee/chaigee,中的z3.py文件 py.txt为团队中文简介文件 代码运行后词频统计使用xlwt库将数据发送到excel ...

  10. ubuntu部署mipsel64交叉编译环境

    最近找到个不错的交叉工具链,据传能够编译mipsel64的程序,决定试试. 首先当然是安装环境: apt install -y gcc libncursesada3-dev 下载,解压,进入 三部曲: ...