多进程多线程并发服务器ppt课件.ppt
- 【下载声明】
1. 本站全部试题类文档,若标题没写含答案,则无答案;标题注明含答案的文档,主观题也可能无答案。请谨慎下单,一旦售出,不予退换。
2. 本站全部PPT文档均不含视频和音频,PPT中出现的音频或视频标识(或文字)仅表示流程,实际无音频或视频文件。请谨慎下单,一旦售出,不予退换。
3. 本页资料《多进程多线程并发服务器ppt课件.ppt》由用户(三亚风情)主动上传,其收益全归该用户。163文库仅提供信息存储空间,仅对该用户上传内容的表现方式做保护处理,对上传内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(点击联系客服),我们立即给予删除!
4. 请根据预览情况,自愿下载本文。本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
5. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007及以上版本和PDF阅读器,压缩文件请下载最新的WinRAR软件解压。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 进程 多线程 并发 服务器 ppt课件
- 资源描述:
-
1、第5章 并发服务器目录n服务器分类n进程与线程n多进程服务器n多线程服务器并发服务器服务器分类n按连接类型分类n面向连接的服务器(如tcp)n面向无连接的服务器(如udp)n按处理方式分类n迭代服务器n并发服务器迭代服务器 vs.并发服务器绑定地址监听连接接收连接处理连接断开连接接收请求处理请求返回响应绑定地址监听连接接收连接创建子进程关闭连接套接字处理连接关闭连接套接字终止子进程关闭监听套接字服务器主进程服务器子进程TCP迭代服务器TCP并发服务器“进程”基本概念n进程定义了一个计算的基本单元,可以认为是一个程序的一次运行。它是一个动态实体,是独立的任务。它拥有独立的地址空间、执行堆栈、文件
2、描述符等。n每个进程拥有独立的地址空间,进程间正常情况下,互不影响,一个进程的崩溃不会造成其他进程的崩溃。n当进程间共享某一资源时,需注意两个问题:同步问题和通信问题。创建进程#include#include pid_t fork(void)返回:父进程中返回子进程的进程返回:父进程中返回子进程的进程ID,子进程返回子进程返回0,-1出错出错nfork后,子进程和父进程继续执行后,子进程和父进程继续执行fork()函数后的指令。()函数后的指令。子进程是父进程的副本。子进程拥有父进程的数据空间、子进程是父进程的副本。子进程拥有父进程的数据空间、堆栈的副本。但父、子进程并不共享这些存储空间部分。
3、堆栈的副本。但父、子进程并不共享这些存储空间部分。如果代码段是只读的,则父子进程共享代码段。如果父子如果代码段是只读的,则父子进程共享代码段。如果父子进程同时对同一文件描述字操作,而又没有任何形式的同进程同时对同一文件描述字操作,而又没有任何形式的同步,则会出现混乱的状况;步,则会出现混乱的状况;n父进程中调用父进程中调用fork之前打开的所有描述字在函数之前打开的所有描述字在函数fork返回返回之后子进程会得到一个副本。之后子进程会得到一个副本。fork后,父子进程均需要将后,父子进程均需要将自己不使用的描述字关闭,有两方面的原因:(自己不使用的描述字关闭,有两方面的原因:(1)以免)以免出
4、现不同步的情况;(出现不同步的情况;(2)最后能正常关闭描述字最后能正常关闭描述字#include#includemain()int i,sum;sum=0;for(i=0;i 0)printf(parent running.n);printf(parent exitn);exit(0);else printf(fork error.n);exit(1);创建进程(cont.)#include#include pid_t vfork(void);n在在BSD3.0中开始出现,主要为了解决中开始出现,主要为了解决fork昂贵的开销。它昂贵的开销。它是完全共享的创建,新老进程共享同样的资源,完全没
5、有拷是完全共享的创建,新老进程共享同样的资源,完全没有拷贝。贝。n两者的基本区别在于当使用两者的基本区别在于当使用vfork()创建新进程时,父进程创建新进程时,父进程将被暂时阻塞,而子进程则可以借用父进程的地址空间。这将被暂时阻塞,而子进程则可以借用父进程的地址空间。这个奇特状态将持续直到子进程退出或调用个奇特状态将持续直到子进程退出或调用execve()函数,函数,至此父进程才继续执行。至此父进程才继续执行。运行的结果:终止进程终止进程n进程的终止存在两个可能:进程的终止存在两个可能:n父进程先于子进程终止(父进程先于子进程终止(init进程领养)进程领养)n子进程先于主进程终止子进程先于
6、主进程终止n对于后者,系统内核为子进程保留一定的状态对于后者,系统内核为子进程保留一定的状态信息:进程信息:进程ID、终止状态终止状态、CPU时间等;当时间等;当父进程调用父进程调用wait或或waitpid函数时,获取这些函数时,获取这些信息;(什么叫信息;(什么叫“僵尸进程僵尸进程”?)?)n当子进程正常或异常终止时,系统内核向其父当子进程正常或异常终止时,系统内核向其父进程发送进程发送SIGCHLD信号;缺省情况下,父进信号;缺省情况下,父进程忽略该信号,或者提供一个该信号发生时即程忽略该信号,或者提供一个该信号发生时即被调用的函数。被调用的函数。终止进程(续)终止进程(续)#inclu
7、de void exit(int status);n本函数终止调用进程。关闭所有子进程打开的描述本函数终止调用进程。关闭所有子进程打开的描述符,向父进程发送符,向父进程发送SIGCHLD信号,并返回状态。信号,并返回状态。获取子进程终止信息获取子进程终止信息#include#include pid_t wait(int*stat_loc);返回:终止子进程的返回:终止子进程的ID成功;成功;-1出错;出错;stat_loc存储存储子进程的终止状态(一个整数);子进程的终止状态(一个整数);n如果没有终止的子进程,但是有一个或多个正在执如果没有终止的子进程,但是有一个或多个正在执行的子进程,则该
8、函数将堵塞,直到有一个子进程行的子进程,则该函数将堵塞,直到有一个子进程终止或者终止或者wait被信号中断时,被信号中断时,wait返回。返回。n当调用该系统调用时,如果有一个子进程已经终止,当调用该系统调用时,如果有一个子进程已经终止,则该系统调用立即返回,并释放子进程所有资源。则该系统调用立即返回,并释放子进程所有资源。获取子进程终止信息获取子进程终止信息在SIGCHLD信号处理函数中使用wait()函数可能会出现一个问题SIGCHLD服务器父进程服务器父进程服务器子进程服务器子进程服务器子进程服务器子进程服务器子进程服务器子进程客户客户FINFINFINSIGCHLDSIGCHLD由于由
9、于linux信号不排队,在信号不排队,在SIGCHLD信号同时到来后,信信号同时到来后,信号处理程序中调用了号处理程序中调用了wait函数,其只执行一次,这样将留函数,其只执行一次,这样将留下下2个僵尸进程。可以使用个僵尸进程。可以使用waitpid函数解决这个问题。函数解决这个问题。获取子进程终止信息获取子进程终止信息pid_t waitpid(pid_t pid,int*stat_loc,int options);返回:终止子进程的返回:终止子进程的ID成功;成功;-1出错;出错;stat_loc存储存储子进程的终止状态;子进程的终止状态;n当当pid=-1,option=0时,该函数等同
10、于时,该函数等同于wait,否则,否则由参数由参数pid和和option共同决定函数行为,其中共同决定函数行为,其中pid参参数意义如下:数意义如下:n-1:要求知道任何一个子进程的返回状态(等待第一:要求知道任何一个子进程的返回状态(等待第一个终止的子进程);个终止的子进程);n0:要求知道进程号为:要求知道进程号为pid的子进程的状态;的子进程的状态;n0)printf(“child%d terminatedn”,pid);waitpid函数用法pid_t pid;if(pid=fork()0)/*parent process*/int child_status;waitpid(pid,&
11、child_status,0);else if(pid=0)/*child process*/exit(0);else /*fork error*/printf(“fork error.n”);exit(1);程序例子:程序例子:#include#include#include int main(void)pid_t pid;int status;if(pid=fork()=0)printf(child running.n);sleep(1);printf(child sleeping.n);printf(child dead.n);exit(0);else if(pid 0)printf(p
12、arent running.n);waitpid(pid,&status,0);printf(parent is runningn);printf(parent exitn);else printf(fork error.n);exit(1);多进程并发服务器状态图服务器客户connect()函数listenfd客户/服务器状态图(调用accept函数时)连接请求多进程并发服务器状态图(cont.)服务器服务器客户客户connect()函数listenfd客户/服务器状态图(调用accept函数后)connfd连接建立多进程并发服务器状态图(cont.)服务器(父进程)服务器(父进程)客户客户
13、connect()函数函数listenfd客户/服务器状态图(调用fork函数后)connfd连接建立连接建立服务器(子进程)listenfdconnfdfork()函数多进程并发服务器状态图(cont.)服务器(父进程)服务器(父进程)客户客户connect()函数函数listenfd客户/服务器状态图(父进程关闭连接套接字,子进程关闭监听套接字)连接建立服务器(子进程)服务器(子进程)connfd多进程并发服务器模板int main(void)int listenfd,connfd;pid_t pid;intBACKLOG=5;if(listenfd=socket(AF_INET,SOCK
14、_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(connfd);.continue;else if(pid=0)/*child process*/close(lisetenfd);.exit(0);els
15、e printf(“fork errorn”);exit(1);一点说明n从以上模板看出,产生新的子进程后,父进程要关闭连接套接字,而子进程要关闭监听套接字,主要原因是:n关闭不需要的套接字可节省系统资源,同时可避免父子进程共享这些套接字可能带来的不可预计的后果;n另一个更重要的原因,是为了正确地关闭连接。和文件描述符一样,每个套接字描述符都有一个“引用计数”。当fork函数返回后,listenfd和connfd的引用计数变为2,而系统只有在某描述符的“引用计数”为0时,才真正关闭该描述符。多进程并发服务器实例n该实例包括服务器程序和客户程序,具体功能如该实例包括服务器程序和客户程序,具体功能
16、如下:下:n服务器等待客户连接请求,连接成功后显示客户地址,服务器等待客户连接请求,连接成功后显示客户地址,并接收该客户的名字并显示,然后接收来自客户的信并接收该客户的名字并显示,然后接收来自客户的信息(字符串)并显示,然后息(字符串)并显示,然后将该字符串反转,将该字符串反转,并将结并将结果送回客户,之后,继续等待接收该客户的信息直至果送回客户,之后,继续等待接收该客户的信息直至该客户关闭连接。要求服务器具有同时处理多个客户该客户关闭连接。要求服务器具有同时处理多个客户的能力。的能力。n客户首先与服务器连接,接着接收用户输入客户的名客户首先与服务器连接,接着接收用户输入客户的名字,并将该名字
17、发送给服务器,接收用户输入的字符字,并将该名字发送给服务器,接收用户输入的字符串,发送给服务器,接收服务器返回的经处理后的字串,发送给服务器,接收服务器返回的经处理后的字符串,并显示之。之后,继续等待用户输入直至用户符串,并显示之。之后,继续等待用户输入直至用户输入输入Ctrl+C,终止连接并退出。,终止连接并退出。多进程并发服务器服务器#include#define PORT1234#define BACKLOG10#define MAXDATASIZE1000void process_cli(int connectfd,struct sockaddr_in client);int main
18、(void)int listenfd,connectfd;pid_tpid;struct sockaddr_intserver,client;int sin_size;/*Create TCP Socket*/if(listenfd=socket(AF_INET,SOCK_STREAM,0)=-1)perror(Create socket failed);exit(-1);int opt=SO_REUSEADDR;setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt);bzero(&server,sizeof(server);s
19、erver.sin_family=AF_INET;server.sin_port=htons(PORT);server.sin_addr.s_addr=htonl(INADDR_ANY);if(bind(listenfd,(struct sockaddr*)&server,serrver)=-1)perror(Bind error);exit(-1);if(listen(listenfd,BACKLOG)=-1)perror(listen error);exit(-1);sin_size=sizeof(struct sockaddr_in);while(1)if(connectfd=accep
20、t(listenfd,(struct sockaddr*)&client,&sin_size)=-1)perror(accept error);exit(-1);if(pid=fork()0)/*parent process*/close(connectfd);continue;else if(pid=0)/*child process*/close(listenfd);process_cli(connectfd,client);exit(0);else printf(fork errorn);exit(0);/*while()*/close(listenfd);/*close listenf
21、d*/多进程并发服务器服务器void process_cli(int connectfd,struct sockaddr_in client)int num;char recvbufMAXDATASIZE,sendbufMAXDATASIZE,cli_nameMAXDATASIZE;printf(“You got a connection from%s.n”,inet_ntoa(client.sin_addr);num=recv(connectfd,cli_name,MAXDATASIZE,0);if(num=0)close(connectfd);printf(“cllient disconn
22、ected.n”);return;cli_namenum=0;printf(“Client name is%s.n”,cli_name);:多进程并发服务器服务器while(num=recv(connectfd,recvbuf,MAXDATASIZE,0)recvbufnum=0;printf(“Received client(%s)message:%sn”,cli_name,recvbuf);for(int i=0;i num;i+)sendbufi=recvbufnum-i-1;sendbufi=0;send(connectfd,sendbuf,strlen(sendbuf),0);clo
23、se(connectfd);多进程并发服务器-运行结果rootsheng sheng#./multiproserverThe server is runningYou got a connection from 222.18.113.153.Client name is shengReceived client(sheng)message:how a yYou got a connection from 127.0.0.1.Client name is limingReceived client(liming)message:abcdReceived client(sheng)message:
展开阅读全文