1 / 34

服务器并发处理

服务器并发处理. 主讲:孟宁 电话:0512-68839302 E-mail:mengning@ustc.edu.cn 主页:http://staff.ustc.edu.cn/~mengning 地址:苏州工业园区独墅湖高等教育区仁爱路166号明德楼A302室. 2010年12月. 服务器并发处理. 并发处理的理解 5种I/O模型 循环服务器 多进程(线程)的并发 I/O复用方式的并发. 并发的概念. 并发有真正的并发( 并行: Parallelism )和表面上的并发( 并发 : Concurrency )(一般采用分时机制). 并行模型. 并发模型.

telyn
Download Presentation

服务器并发处理

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 服务器并发处理 主讲:孟宁 电话:0512-68839302 E-mail:mengning@ustc.edu.cn 主页:http://staff.ustc.edu.cn/~mengning 地址:苏州工业园区独墅湖高等教育区仁爱路166号明德楼A302室 2010年12月

  2. 服务器并发处理 • 并发处理的理解 • 5种I/O模型 • 循环服务器 • 多进程(线程)的并发 • I/O复用方式的并发

  3. 并发的概念 • 并发有真正的并发(并行: Parallelism)和表面上的并发(并发:Concurrency)(一般采用分时机制) 并行模型 并发模型

  4. 网络中的并发 • 单个网络各个机器之间许多成对进程好像独立使用网络资源(通道,机器等) • 一个计算机系统中存在并发(分时) • 一组机器上所有的客户之间存在并发 互联网 C1 C3 C2 C4 C5

  5. 服务器中的并发 • 单个服务器必须并发处理多个传入请求 • 并发服务器可以让多个远程用户同时使用服务,实现起来比较复杂 C1 互联网 服务器 C2 C3 C4

  6. 操作系统的并发功能 • 多进程操作系统 • 进程的概念:进程定义了一个计算的基本单元,它是一个执行某一个特定程序的实体,它拥有独立的地址空间、执行堆栈、文件描述符等。 • 多线程细化了并发处理的粒度,也给编程带来了新的困难 - 维护函数的可重入性

  7. 创建进程 #include <sys/types.h> #include <unistd.h> pid_t fork(void) 返回:父进程中返回子进程的进程ID, 子进程返回0,-1-出错(注意为什么?) • fork后,父子进程共享数据空间、代码空间、堆栈、所有的文件描述字;

  8. 程序的并发版本fork #include <unistd.h> #include <stdio.h> #include <sys/types.h> int main () { pid_t pid; pid=fork(); if (pid < 0) printf("error in fork!"); else if (pid == 0) printf("i am the child process, my process id is %d\n",getpid()); else printf("i am the parent process, my process id is %d\n",getpid()); }

  9. 阻塞I/O模型

  10. 非阻塞I/O模型

  11. I/O复用模型

  12. 信号驱动I/O模型

  13. 异步I/O模型

  14. 5种I/O模型的比较

  15. I/O复用-select/poll • 某些OS允许单个线程控制并发的输入输出操作 • 使用select询问操作系统I/O设备的情况 • 例子: • 用户从TCP接收数据并且显示,还允许用户从键盘输入命令控制显示。 • 两个输入:TCP, 键盘 • 总是等着一个输入,会阻塞 • 使用select/poll询问输入是否就绪

  16. select Function #include <sys/select.h> #include <sys/time.h> int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout); Returns: positive count of ready descriptors, 0 on timeout, –1 on error void FD_ZERO(fd_set *fdset); /* clear all bits in fdset */ void FD_SET(int fd, fd_set *fdset); /* turn on the bit for fd in fdset */ void FD_CLR(int fd, fd_set *fdset); /* turn off the bit for fd in fdset */ int FD_ISSET(int fd, fd_set *fdset); /* is the bit for fd on in fdset ? */

  17. poll Function #include <poll.h> int poll (struct pollfd *fdarray, unsigned long nfds, int timeout); Returns: count of ready descriptors, 0 on timeout, –1 on error struct pollfd { int fd; /* descriptor to check */ short events; /* events of interest on fd */ short revents; /* events that occurred on fd */ };

  18. 服务器软件设计概述 • 无连接和面向连接的服务器访问 • 无状态和有状态的服务器应用 • 循环和并发的服务器的实现 • 简单服务器的算法: • 创建套接字 • 绑定到一个熟知端口 • 期望在这个端口上接收请求 • 进入无限循环,接受客户请求并应答 • 只适用于最简单的服务…

  19. 并发服务器和循环服务器 • 循环服务器:一个时刻只处理一个请求 • 并发服务器:一个时刻可以处理多请求 • 多数只提供表面并发:执行多个线程,每个线程处理一个请求 • 使用单线程的可能性:计算量小,主要是异步I/O, 便于同时使用多个通信信道 • 并发处理多个请求,而不是指下层是否使用了多个并发线程 • 循环服务器容易构建,但是性能差;并发服务器难以构建和设计,但是性能好

  20. 四种基本类型的服务器 • 循环的或者并发的 • 使用面向连接的或者无连接的传输

  21. 将套接字置于被动模式 • 调用listen:将套接字置于被动模式 • 一个参数指明套接字内部的请求队列长度 • 请求队列保存一组TCP传入连接请求,来自客户,都向这个服务器请求一个连接 • 接收连接并使用这些连接 • 调用accept:获得下一个传入连接请求 • 返回新的连接的套接字的描述符 • 服务器接收连接,使用read获得来自客户的应用协议,使用write发回应答。 • 服务器结束连接,使用close释放套接字

  22. 循环服务器概述 • 循环服务器的类型 • 使用无连接传输,常见 • 使用面向连接的服务 • 循环无连接服务器 • 使用无连接的循环服务器 • chatsys socketwraper hello回射服务的例子 • 循环面向连接的服务器 • 循环的面向连接的服务器 • daytime服务的例子 • 特点: • 每次处理时间都很少 • 服务器实现简单 函数的具体使用方法请大家查阅相关资料。

  23. 无连接循环服务器的算法 • 循环服务器的设计,编程,排错,修改很容易。往往使用无连接的协议。 • 循环服务器对于小的处理时间的服务工作很好。 • 无连接服务器算法如下: • 1、创建套接字并将其绑定到所提供服务的熟知端口上; • 2、重复读取来自客户的请求,构造响应,按照应用协议向客户发回响应。

  24. serverfd=socket(AF_INET,SOCK_DGRAM,0); bzero(&servaddr,sizeof(struct sockaddr_in)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(SERVER_PORT); bind(serverfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in)); while(1) { recvfrom(serverfd,msg,MAX_MSG_SIZE,0,(struct sockaddr*)&clientaddr,&addrlen); sendto(serverfd,msg,i4PduSize,0,(struct sockaddr*)&clientaddr,sizeof(struct sockaddr_in)); }

  25. 并发服务器的算法 • 给多个客户提供快速响应时间需要使用并发服务器 • 有相当的I/O时间的响应 • 可以部分重叠地使用处理器和外设 • 各个请求所要求的处理时间变化很大 • 时间分片允许单个处理那些只要求少量处理的请求尽快完成 • 服务器运行在具有多个处理器的计算机上 • 不同的处理器处理不同的请求 • 并发服务器通过使处理和I/O部分重叠来达到高性能。

  26. 主线程和从线程 • 尽管可以使用一个单线程实现并发服务器,但是大多数使用多线程: • 主线程最先开始执行在熟知的端口上打开一个套接字,等待一个请求,并为每个请求创建一个从线程(可能在一个新进程中) • 主线程不与客户直接通信,每个从线程处理一个客户的通信。 • 从线程构成响应并发送给客户后,这个从线程便退出

  27. 并发的无连接的服务器的算法 • 最简单的算法: • 主1、创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持为未连接的 • 主2、反复调用recvfrom接收来自客户的下一个请求,创建一个新的从线程来处理响应 • 从1、从来自主进程的特定请求以及到该套接字的访问开始 • 从2、根据应用协议构造应答,并用sendto将该应答发回给客户 • 从3、退出(即:从线程处理完一个请求后就终止) • 由于创建进程或者线程是昂贵的,因此只有很少的无连接服务器采用并发实现

  28. pthread_t pid; serverfd=socket(AF_INET,SOCK_DGRAM,0); bzero(&servaddr,sizeof(struct sockaddr_in)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(SERVER_PORT); bind(serverfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in)); while(1) { recvfrom(serverfd,msg,MAX_MSG_SIZE,0,(struct sockaddr*)&clientaddr,&addrlen); if(pthread_create(&pid, NULL,(void*)sub_task, (void*)&serverfd) != OK) perror("pthread_create"); } } void * sub_task(void * fd) { sendto }

  29. 并发的面向连接服务器算法 • 面向连接的服务器在多个连接之间实现并发(不是在各个请求之间) • 主1、创建套接字并将其绑定到所提供服务的熟知地址上。让该套接字保持为面向连接 • 主2、将该端口设置为被动模式 • 主3、反复调用accept以便接收来自客户的下一个连接请求,并创建新的从线程或者进程来处理响应 • 从1、由主线程传递来的连接请求开始 • 从2、用该连接与客户进行交互;读取请求并发回响应 • 从3、关闭连接并退出

  30. pthread_t pid; int listenfd, connfd; listenfd = Socket( ... ); /* fill in sockaddr_in{} with server's well-known port */ Bind(listenfd, ... ); Listen(listenfd, LISTENQ); for ( ; ; ) { connfd = Accept (listenfd, ... ); /* probably blocks */ if(pthread_create(&pid, NULL,(void*)sub_task, (void*)&listenfd) != OK) perror("pthread_create"); } Close(connfd); /* parent closes connected socket */ } void * sub_task(void * listenfd) { doit(listenfd); /* process the request */ Close(listenfd); /* done with this client */ }

  31. 各个服务器使用的场合 • 循环的和并发的: • 如果循环方案产生的响应时间对应用来说足够,就可以使用循环;否则需要并发 • 真正的和表面上的并发性: • 线程或切换环境的开销大,服务器需要在多个连接之间共享或者交换数据,用单线程; • 使用线程开销不大或者要得到最大并发性,使用多进程 • 面向连接的和无连接的: • 应用协议处理了可靠性问题,或者应用在局域网环境内,使用无连接的传输。

  32. 服务器死锁 • 循环的面向连接的服务器: • 某个客户和服务器建立一个连接,客户不再发送请求,服务器无法使用recv得到请求,服务器将在这里阻塞 • 客户不能正常工作,不处理服务器的响应,将导致服务器的外发存储数据区填满阻塞 • 可能阻塞的系统调用会产生死锁 • 单线程的服务器会被阻塞死锁

  33. 服务器类型小结 • 循环无连接服务器 • 请求要求处理少,无状态的,最常见的 • 循环的面向连接服务器 • 要求可靠传输的,对请求要求处理少的服务,较常见 • 并发的,无连接的服务器 • 不常见,为每个请求创建一个新线程或进程 • 并发的面向连接的服务器 • 最一般的。可靠传输,并发处理多个请求 • 多线程(进程)

  34. 祝大家能得到自我成长!

More Related