多进程多线程并发服务器

上传人:tia****nde 文档编号:66947786 上传时间:2019-01-06 格式:PPT 页数:68 大小:462.51KB
返回 下载 相关 举报
多进程多线程并发服务器_第1页
第1页 / 共68页
多进程多线程并发服务器_第2页
第2页 / 共68页
多进程多线程并发服务器_第3页
第3页 / 共68页
多进程多线程并发服务器_第4页
第4页 / 共68页
多进程多线程并发服务器_第5页
第5页 / 共68页
点击查看更多>>
资源描述

《多进程多线程并发服务器》由会员分享,可在线阅读,更多相关《多进程多线程并发服务器(68页珍藏版)》请在金锄头文库上搜索。

1、第5章 并发服务器,目录 服务器分类 进程与线程 多进程服务器 多线程服务器,并发服务器,服务器分类,按连接类型分类 面向连接的服务器(如tcp) 面向无连接的服务器(如udp) 按处理方式分类 迭代服务器 并发服务器,迭代服务器 vs. 并发服务器,绑定地址,监听连接,接收连接,处理连接,断开连接,接收请求,处理请求,返回响应,绑定地址,监听连接,接收连接,创建子进程,关闭连接套接字,处理连接,关闭连接套接字,终止子进程,关闭监听套接字,服务器主进程,服务器子进程,TCP迭代服务器,TCP并发服务器,“进程”基本概念,进程定义了一个计算的基本单元,可以认为是一个程序的一次运行。它是一个动态实

2、体,是独立的任务。它拥有独立的地址空间、执行堆栈、文件描述符等。 每个进程拥有独立的地址空间,进程间正常情况下,互不影响,一个进程的崩溃不会造成其他进程的崩溃。 当进程间共享某一资源时,需注意两个问题:同步问题和通信问题。,创建进程,#include #include pid_t fork(void) 返回:父进程中返回子进程的进程ID, 子进程返回0, -1出错 fork后,子进程和父进程继续执行fork()函数后的指令。子进程是父进程的副本。子进程拥有父进程的数据空间、堆栈的副本。但父、子进程并不共享这些存储空间部分。如果代码段是只读的,则父子进程共享代码段。如果父子进程同时对同一文件描述

3、字操作,而又没有任何形式的同步,则会出现混乱的状况; 父进程中调用fork之前打开的所有描述字在函数fork返回之后子进程会得到一个副本。fork后,父子进程均需要将自己不使用的描述字关闭,有两方面的原因:(1)以免出现不同步的情况;(2)最后能正常关闭描述字,#include #include main() int i, sum; sum = 0; for(i =0;i=2;i+) sum = sum +i; printf(“i=%dn“,i); printf(“sum = %dn“,sum); ,int main(void) pid_t pid; int status; if (pid =

4、 fork() = 0) sleep(2); printf(“child running.n“); printf(“child sleeping.n“); sleep(2); printf(“child dead.n“); exit(0); else if ( pid 0) printf(“parent running .n“); printf(“parent exitn“); exit(0); else printf(“fork error.n“); exit(1); ,创建进程(cont.),#include #include pid_t vfork(void); 在BSD3.0中开始出现

5、,主要为了解决fork昂贵的开销。它是完全共享的创建,新老进程共享同样的资源,完全没有拷贝。 两者的基本区别在于当使用vfork()创建新进程时,父进程将被暂时阻塞,而子进程则可以借用父进程的地址空间。这个奇特状态将持续直到子进程退出或调用execve()函数,至此父进程才继续执行。,int main(void) pid_t pid; int status; if (pid = vfork() = 0) sleep(2); printf(“child running.n“); printf(“child sleeping.n“); sleep(2); printf(“child dead.n“

6、); exit(0); else if ( pid 0) printf(“parent running .n“); printf(“parent exitn“); exit(0); else printf(“fork error.n“); exit(1); ,运行的结果:,终止进程,进程的终止存在两个可能: 父进程先于子进程终止(init进程领养) 子进程先于主进程终止 对于后者,系统内核为子进程保留一定的状态信息:进程ID、终止状态、CPU时间等;当父进程调用wait或waitpid函数时,获取这些信息;(什么叫“僵尸进程”?) 当子进程正常或异常终止时,系统内核向其父进程发送SIGCHLD

7、信号;缺省情况下,父进程忽略该信号,或者提供一个该信号发生时即被调用的函数。,终止进程(续),#include void exit(int status); 本函数终止调用进程。关闭所有子进程打开的描述符,向父进程发送SIGCHLD信号,并返回状态。,获取子进程终止信息,#include #include pid_t wait(int *stat_loc); 返回:终止子进程的ID成功;-1出错;stat_loc存储子进程的终止状态(一个整数); 如果没有终止的子进程,但是有一个或多个正在执行的子进程,则该函数将堵塞,直到有一个子进程终止或者wait被信号中断时,wait返回。 当调用该系统调

8、用时,如果有一个子进程已经终止,则该系统调用立即返回,并释放子进程所有资源。,获取子进程终止信息,在SIGCHLD信号处理函数中使用wait()函数可能会出现一个问题,SIGCHLD,由于linux信号不排队,在SIGCHLD信号同时到来后,信号处理程序中调用了wait函数,其只执行一次,这样将留下2个僵尸进程。可以使用waitpid函数解决这个问题。,获取子进程终止信息,pid_t waitpid(pid_t pid, int *stat_loc, int options); 返回:终止子进程的ID成功;-1出错;stat_loc存储子进程的终止状态; 当pid=-1,option=0时,该

9、函数等同于wait,否则由参数pid和option共同决定函数行为,其中pid参数意义如下: -1:要求知道任何一个子进程的返回状态(等待第一个终止的子进程); 0:要求知道进程号为pid的子进程的状态; -1: wait for any child process whose process group ID is equal to the absolute value of pid. Options最常用的选项是WNOHANG,它通知内核在没有已终止进程时不要堵塞。,获取子进程终止信息(cont.),调用wait或waitpid函数时,正常情况下,可能会有以下几种情况: 阻塞(如果其所有子

10、进程都还在运行); 获得子进程的终止状态并立即返回(如果一个子进程已终止,正等待父进程存取其终止状态); 出错立即返回(如果它没有任何子进程),pid_t pid; int stat; while(pid=waitpid(-1,waitpid函数用法,pid_t pid; if (pid=fork() 0) /* parent process */ int child_status; waitpid(pid, ,程序例子: #include #include #include int main(void) pid_t pid; int status; if (pid = fork() = 0)

11、 printf(“child running.n“); sleep(1); printf(“child sleeping.n“); printf(“child dead.n“); exit(0); ,else if ( pid 0) printf(“parent running .n“); waitpid(pid, ,多进程并发服务器状态图,服务器,客户,connect()函数,listenfd,客户/服务器状态图(调用accept函数时),连接请求,多进程并发服务器状态图(cont.),服务器,客户,connect()函数,listenfd,客户/服务器状态图(调用accept函数后),co

12、nnfd,连接建立,多进程并发服务器状态图(cont.),服务器(父进程),客户,connect()函数,listenfd,客户/服务器状态图(调用fork函数后),connfd,连接建立,服务器(子进程),listenfd,connfd,fork()函数,多进程并发服务器状态图(cont.),服务器(父进程),客户,connect()函数,listenfd,客户/服务器状态图(父进程关闭连接套接字,子进程关闭监听套接字),连接建立,服务器(子进程),connfd,多进程并发服务器模板, int main(void) int listenfd, connfd; pid_t pid; int B

13、ACKLOG = 5; if (listenfd = socket(AF_INET, SOCK_STREAM, 0) = -1) perror(“Create socket failed.”); exit(1); bind(listenfd, ); listen(listenfd, BACKLOG); while(1) if (connfd = accept(sockfd, NULL, NULL) = -1) perror(“Accept error.”); exit(1); ,多进程并发服务器模板,if(pid = fork() ) 0) /*parent process */ close(

14、connfd); . continue; else if (pid = 0) /*child process */ close(lisetenfd); . exit(0); else printf(“fork errorn”); exit(1); ,一点说明,从以上模板看出,产生新的子进程后,父进程要关闭连接套接字,而子进程要关闭监听套接字,主要原因是: 关闭不需要的套接字可节省系统资源,同时可避免父子进程共享这些套接字可能带来的不可预计的后果; 另一个更重要的原因,是为了正确地关闭连接。和文件描述符一样,每个套接字描述符都有一个“引用计数”。当fork函数返回后,listenfd和connf

15、d的引用计数变为2,而系统只有在某描述符的“引用计数”为0时,才真正关闭该描述符。,多进程并发服务器实例,该实例包括服务器程序和客户程序,具体功能如下: 服务器等待客户连接请求,连接成功后显示客户地址,并接收该客户的名字并显示,然后接收来自客户的信息(字符串)并显示,然后将该字符串反转,并将结果送回客户,之后,继续等待接收该客户的信息直至该客户关闭连接。要求服务器具有同时处理多个客户的能力。 客户首先与服务器连接,接着接收用户输入客户的名字,并将该名字发送给服务器,接收用户输入的字符串,发送给服务器,接收服务器返回的经处理后的字符串,并显示之。之后,继续等待用户输入直至用户输入Ctrl+C,终

16、止连接并退出。,多进程并发服务器服务器,#include #define PORT 1234 #define BACKLOG 10 #define MAXDATASIZE 1000 void process_cli(int connectfd, struct sockaddr_in client); int main(void) int listenfd, connectfd; pid_t pid; struct sockaddr_int server, client; int sin_size; /* Create TCP Socket */ ,if(listenfd=socket(AF_INET

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号