1、Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,*,*,段景山,网络软件设计,并发服务与重复服务,Concurrent Service,Repeating Service,制作,主讲,段景山,1,、基本思想,1.1,重复服务,仅使用一个服务器进程依次为每个用户服务,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,
2、recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,监听,套接字,连接服务,套接字,连接服务,套接字,连接服务,套接字,循环,重复,2,基本思想,1.2,并发服务,利用多个进程“同时”为各用户请求服务,主进程,子进程,1,子进程,2,监听,套接字,创建,连接服务,套接字,连接服务,套接字,相关知识,进程,线程,并发,并行,多任务系统调度,*单,CPU,系统,监听到连接,3,基本思想,1.3,两种服务方式的比较,程序结构,重复服务:轮询,并发服务:主、子进程,同时并发,系统效率,查询的效率,进程调度,上下文切换的开销,实现的难易度,特
3、别在多个用户接入的情况,例,用户接入系统输入用户名,口令,重复服务必须,统一管理每个,套接字的通信状态,并发服务下,一个线程(进程)一般只对应一个套接字,不需要统一管理,但涉及线程的控制,4,2,、实现,2,重复服务方式的实现,2.1,非多路复用,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,5,重复服务实现,2,重复服务方式的实现,2.2,多路复用,select,(),while(
4、1),while(recv(s,buf1,)0),while(select,(0,&readfds,0,0,&tmo),if(,FD_ISSET(s,&,readfds,),FD_SET(ss,&,readfds,);,生成查询队列,if(FD_ISSET(s,&,writefds,),get s from sockets queue,6,重复服务实现,2.3,重复服务多路复用流程,recv,处理数据,准备接收,新数据,关闭连接,END,收到,出错,没有,select,(,,,timeout,),准备发送,其它,sock_id,事件,7,并发服务实现,3,并发服务方式的实现,3.1,并发服务程
5、序流程,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns,=,accept(s,);,closesocket(s,);,主进程,创建子进程,,并将,ns,传递给子进程,子进程(,ns,),while,(,recv,(,ns,,,)0),printf(buf,);,send(,ns,”ACK,”,);,closesocket(,ns,);,关键技术,完成通信,父进程为每一条连接,生成一个子进程,每个子进程在相应的,连接上完成通信,8,并发服务实现,3.2 UNIX,并发服务的实现,3.2.1fork,(),main,(),in
6、t,i;,sum=0;,fork,();,for,(,i,1;i=10000;i+,),printf,(,”,the value of i is%d“,i,);,fflush,(,stdout,);,sum,i,;,printf,(“the total is%,d”,sum,);,exit(0);,fork():,创建一个新进程,,新进程是父进程的复制品数据、代码,因此新进程将完成和父进程同样的功能,.,9,main,(),int,i;,sum=0;,fork,();,for,(,i,1;i=10000;i+,),printf,(,”,the value of i is%d“,i,);,ffl
7、ush,(,stdout,);,sum,i,;,printf,(“the total is%,d”,sum,);,exit(0);,并发服务实现,main,(),int,i;,sum=0;,fork,();,for,(,i,1;i=10000;i+,),printf,(,”,the value of i is%d“,i,);,fflush,(,stdout,);,sum,i,;,printf,(“the total is%,d”,sum,);,exit(0);,主进程,子进程,子进程从这里开始,10,并发服务的实现,执行结果,main,(),int,i;,sum=0;,fork,();,for
8、i,1;i=10000;i+,),printf,(,”,the value of i is%d,n“,i,);,fflush,(,stdout,);,sum,i,;,printf,(“the total is%,d”,sum,);,exit(0);,the value of i is 1,the value of I is 2,the value of i is 3,the value of i is 4,the value of i is 1,the value of I is 2,the value of i is 3,the value of i is 4,the value of
9、 i is 5,the value of I is 6,the value of i is 7,the value of i is 5,the value of i is 6,the value of I is 7,the value of i is 8,the value of i is 8,主,/,子进程并发执行(分时调度),进程,x,进程,y,进程,x,进程,y,思考:,sum,的结果,11,并发服务的实现,3.2.2 fork(),与并发服务,main,(),int,i;,sum=0;,fork,();,for,(,i,1;i=10000;i+,),printf,(,”,the val
10、ue of i is%d,n“,i,);,fflush,(,stdout,);,sum,i,;,printf,(“the total is%,d”,sum,);,exit(0);,Back,初始化,主要工作,Server,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,建立连接,通信,fork,();,12,并发服务的实现,Server,s=socket(,SOCK_STREAM,);
11、bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,fork();,Server,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,fork();,问题:如何使主,/,子进程完成不同的工作?,主进程:不断建立连接,创建子进程,子进
12、程:完成连接上的通信,13,并发服务的实现,3.2.3,进程的分离,新进程执行与父进程不同的代码,利用,fork,()的返回值。,fork,()后,父进程得到的返回值为子进程标识符,fork,()后,子进程得到的返回值为,0,为新进程更换代码,fork,();,execve,();,14,并发服务的实现,利用,fork,返回值分离进程,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,recv(ns,);,send(ns,);,closesocket(ns,);,closesocket(s,);,f
13、ork();,pid,=fork();,if(pid,=0),closesocket(s,),recv(ns,);,send(ns,);,exit(0);,else,closesocket,(ns);,思考:主进程与子进程是如何分离的?,为什么在子进程中要关闭,s,为什么在主进程中要关闭,ns,子进程如何结束,父进程如何结束,子进程,父进程,15,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,pid,=fork();,if(,pid,=0),closesocket(s,),recv(ns,);,
14、send(ns,);,exit(0);,else,closesocket,(ns);,SOCKET,s,ns,;,int,pid,;,并发服务的实现,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,pid,=fork();,if(,pid,=0),closesocket(s,),recv(ns,);,send(ns,);,exit(0);,else,closesocket,(ns);,主进程,子进程,SOCKET,s,ns,;,int,pid,;,系统往,pid,中放入子进程,id,系统往,pid
15、中放入,0,16,并发服务的实现,用,execve,()替换子进程代码,可以使子进程具有与父进程不同的代码,int,execve,(const char*,pathname,const,char*,argv,const char*,envp,),pathname:,子进程执行的程序路径名,argv,:,传递给子进程的参数表,envp,:,指定子进程的新环境,17,并发服务的实现,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,pid,=fork();,if(pid,=0),closesocket
16、s);,argv1=ns;,execve(“user/bin/chat”,argv,NULL,);,else,closesocket,(ns);,Chat.c,main(argc,argv,),SOCKET s;,s=argv1;,recv(s,);,send(s,);,closesocket(s,);,18,并发服务的实现,3.3 Windows,并发服务的实现,CreateThread,生成线程,CreatePorcess,生成进程,线程执行指定的代码段,线程之间并发执行,与,UNIX,下的,fork,(),execve,方法类似,相关知识:线程与进程的区别和联系,19,并发服务的实现
17、3.3.1,CreateThread,HANDLE,CreateThread,(,LPSECURITY_ATTRIBUTES,lpThreadAttributes,DWORD,dwStackSize,LPTHREAD_START_ROUTINE,lpStartAddress,LPVOID,lpParameter,DWORD,dwCreationFlags,LPDWORD,lpThreadId,);,lpStartAddress,:,线程代码入口点线程函数指针,lpParameter,:传递给线程的参数,lpThreadId,:线程标识符返回值,函数返回值:线程句柄,20,并发服务的实现,DW
18、ORD WINAPI,ThreadFunc,(LPVOID,lpParam,),char szMsg80;,wsprintf,(,szMsg,ThreadFunc,:Parameter=%,dn,*,lpParam,);,MessageBox,(NULL,szMsg,Thread created.,MB_OK);,return 0;,VOID main(VOID),DWORD,dwThreadId,dwThrdParam,=1;,HANDLE,hThread,;,hThread,=,CreateThread,(NULL,0,ThreadFunc,&,dwThrdParam,0,&,dwThre
19、adId,);,/returns the thread identifier,/Check the return value for success.,if(,hThread,=NULL),ErrorExit,(,CreateThread,failed.);,CloseHandle,(,hThread,);,生成线程的例程,21,并发服务的实现,3.3.2,主进程代码,s=socket(,SOCK_STREAM,);,bind(s,);,listen(s,5);,while(1),ns=,accept(s,);,pid,=fork();,if(pid,=0),closesocket,(s);,
20、argv1=ns;,execve(“user/bin/chat”,NULL,NULL,);,else,closesocket,(ns);,CreateThread,(NULL,0,chat,/,子线程函数入口,&,param,/,传给子线程的参数,0,&,Tid,);,param,=ns;,22,并发服务的实现,3.3.3,线程代码,DWORD WINAPI,chat(LPVOID,param,),SOCKET s;,s=(SOCKET)*,param,;,recv,(s,);,send(s,),while(1),closesocket,(s);,23,小结,并发服务机制具有多路复用功能,并发
21、执行的进程,/,线程同时为多条连接服务,并发服务与上下文切换,在并发执行的进程间调度,需要消耗系统资源,多路复用的实现方法,事件驱动的重复服务,select,生成子进程的并发服务,24,并发服务实验,实验目的,编写并发服务机制的服务器程序,感受多线程并发服务的效果,实验原理与方法,并发服务具有多路复用特点,通过执行程序感受,通过,spy,查找线程存在的证据,实验过程,1,、完成程序,将连接建立后的通信程序段作为一个函数调用,以方便对比实验,2,、不建立线程,服务器程序是否能提供多路复用,3,、建立线程,服务器程序能否提供多路复用,4,、利用,Spy,查看线程,是否能找到多个服务器线程,当有,n
22、个客户与服务器建立了连接,服务器线程数为,将线程号记录下来以便查询,25,性能瓶颈,每个线程或者进程只能监听一个连接,如果要处理成千上万个连接?,一个线程能够处理,64,个连接,多开一些线程或者进程就能够提高并行处理能力,26,3.4,节的基本想法,使用,WSAEventSelect,函数,在一个线程中最多可以同时侦听,64,个,socket,同时开多个线程来增加处理能力。,在主线程中,监听,socket,,每新到一个连接请求,,分配到一个有能力的线程中,如实在找不到则新建一个线程。,在线程中实现多个,socket,的通信任务,27,数据结构,建立一个线程列表,每一个,threadobj,记录一个线程的工作信息,如图,3.2,所示,Event,数组:每个线程侦听的,socket,都要与一个,event,关联。,Psocket,链表:线程侦听的,socket,表。,Nsocketcount,:线程侦听的连接数目,28,见教材程序,29,






