下面有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. 【Rain in ACStar HDU-3340】

    ·你正从AC星球返回,天又下起凸包雨,只好到线段树下躲雨. ·英文题,述大意:       一个竖直平面的美丽天空,会下凸包雨.凸包雨指的是边数为3~6的多边形,并且每一个它都遵守一个神奇定律,那就是 ...

  2. k-d树模板(BZOJ2648)

    实现了插入一个点,查询距某个位置的最近点. #include <cstdio> #include <algorithm> using namespace std; , inf ...

  3. Nginx+uWSGI+Django环境配置

    通常项目会部署在虚拟环境,虚拟环境的使用可以参考这里,点击前往 当然你也可以直接部署,这里不多说. 一.安装uWSGI 1.通过pip安装 pip install uwsgi 这里只说明了一种安装方式 ...

  4. 【Git】CentOS7 通过源码安装Git

    yum源仓库里的Git版本更新不及时,最新版的Git是1.8.3,但是官方的最新版早已经更新到2.9.5.想要安装最新版本Git,只能下载源码进行安装 建议最好更新git为较新版本,便于使用 1.查看 ...

  5. 华科机考:IP地址

    时间限制:1秒  空间限制:32768K 题目描述 输入一个ip地址串,判断是否合法. 输入描述: 输入的第一行包括一个整数n(1<=n<=500),代表下面会出现的IP地址的个数. 接下 ...

  6. c语言第六次作业v

    (一)改错题 序列求和:输入一个正实数eps,计算序列部分和 1 - 1/4 + 1/7 - 1/10 + ... ,精确到最后一项的绝对值小于eps(保留6位小数). 输入输出样例: Input e ...

  7. A neural chatbot using sequence to sequence model with attentional decoder. This is a fully functional chatbot.

    原项目链接:https://github.com/chiphuyen/stanford-tensorflow-tutorials/tree/master/assignments/chatbot 一个使 ...

  8. PHP+JQuery+Ajax初始化网站基本信息(附源码)--PHP

    一.思路 为了保存用户会员信息的时间长一些,不局限于session的关闭.我们需要将用户信息保存在数据库中,前台每次登录都需要进行校验,来查看用看用户会员信息是否过期,如果没有过期,取出用户会员信息存 ...

  9. vue环境搭建过程中,遇到的坑爹的问题

    1,在配置package.json下载node依赖包时,执行$cnpm install过程中,这个过程是比较漫长的,尤其的这种core i5配置的电脑,简直有点卡的人怀疑人生,后来动了下有消息输出,我 ...

  10. Python小代码_2_格式化输出

    Python小代码_2_格式化输出 name = input("name:") age = input("age:") job = input("jo ...