《网络计算编程》第五讲循环服务器电子科技大学信软学院循环服务器概述1.循环服务器的类型①使用无连接传输,常见②使用面向连接的服务2.循环无连接服务器①使用无连接的循环服务器,采用算法8.2②TIME服务的例子3.循环面向连接的服务器①循环的面向连接的服务器,采用算法8.1②DAYTIME服务的例子4.特点:①每次处理时间都很少②服务器实现简单创建被动的套接字(passivesock.c)1.创建一个过程隐藏创建一个被动套接字的细节①获得熟知的端口号,端口号的唯一性问题。②使用什么协议a)passiveTCP:使用面向连接的被动套接字b)passiveUDP:本章学习,使用无连接的被动套接字③绑定IP地址2.passivesock①三个参数第一个服务名,第二个协议名,第三个参数指明连接请求队列所需要的长度(只用于TCP套接字)②使用INADDR_ANY代替特定的本地IP地址③getservbyname,strcmp,memset,socket,bind,listen…intpassivesock(constchar*service,constchar*transport,intqlen){structservent*pse;structsockaddr_insin;ints,type;memset(&sin,0,sizeof(sin));sin.sin_family=AF_INET;sin.sin_addr.s_addr=INADDR_ANY;if(pse=getservbyname(service,transport))sin.sin_port=htons(pse-s_port);elseif((sin.sin_port=htons((unsignedshort)atoi(service)))==0)errexit(can'tget\%s\serviceentry\n,service);if(strcmp(transport,udp)==0)type=SOCK_DGRAM;elsetype=SOCK_STREAM;if((s=socket(PF_INET,type,0))0)errexit(can'tcreatesocket:%s\n,strerror(errno));if(bind(s,(structsockaddr*)&sin,sizeof(sin))0)errexit(can'tbindto%sport:%s\n,service,strerror(errno));if(type==SOCK_STREAM&&listen(s,qlen)0)errexit(can'tlistenon%sport:%s\n,service,strerror(errno));returns;}创建被动的套接字1.passiveUDP调用passivesock实现2.passiveTCP调用passivesock实现创建被动的UDP套接字(passiveUDP)intpassiveUDP(constchar*service)/**Arguments:*service-serviceassociatedwiththedesiredport*/{returnpassivesock(service,udp,0);}创建被动的TCP套接字(passiveTCP)intpassiveTCP(constchar*service,intqlen)/**Arguments:*service-serviceassociatedwiththedesiredport*qlen-maximumserverrequestqueuelength*/{returnpassivesock(service,tcp,qlen);}进程结构循环的无连接的服务器进程结构只需要一个执行线程用于所有通信的熟知套接字端口服务器操作系统服务器应用进程TIME服务器举例1.客户使用TIME服务从另一个系统得到当前时间(前面已经讨论过)2.TIME服务几乎不需要什么计算3.UDPtimed.cpage91①头文件include②宏定义,变量定义,函数声明③main函数a)参数分析b)调用passiveUDPc)recvfrom,sendto循环循环无连接服务器小结1.使用这个服务器的原因①简单服务②服务器为每个请求的计算很少2.循环服务器是个简单的服务器3.建立被动的套接字的过程4.TIME服务①获得系统时间服务②使用UDP访问③编程方法循环的面向连接的服务器分配被动的TCP套接字1.调用passivesock实现2.带有两个参数①第一个是字符串:服务的名字或者端口号②传入连接的请求队列所需的长度用于DAYTIME服务的服务器1.DAYTIME服务:从另外机器上获得当前的日期和时间(前面第7章已经谈过)2.DAYTIME服务器不需要优化速率①获取和格式化日期要求很少的处理②用户对此服务的需求很少3.循环实现就足够了服务器忙的时候,其他的请求可以排队进程的结构1.使用一个单执行线程2.使用两个套接字①一个套接字处理请求②另外一个套接字处理和客户的通信(临时的)用于连接请求的套接字服务器操作系统服务器应用进程用于单个连接的套接字intmain(intargc,char*argv[]){structsockaddr_infsin;/*thefromaddressofaclient*/char*service=daytime;/*servicenameorportnumber*/intmsock,ssock;/*master&slavesockets*/unsignedintalen;/*from-addresslength*/switch(argc){case1:break;case2:service=argv[1];break;default:errexit(usage:TCPdaytimed[port]\n);}msock=passiveTCP(service,QLEN);while(1){alen=sizeof(fsin);if((ssock=accept(msock,(structsockaddr*)&fsin,&alen))0)errexit(acceptfailed:%s\n,strerror(errno));TCPdaytimed(ssock);(void)close(ssock);}}VoidTCPdaytimed(intfd){char*pts;time_tnow;char*ctime();(void)time(&now);pts=ctime(&now);(void)write(fd,pts,strlen(pts));}DAYTIME服务器例子TCPdaytimed.cpage961.passiveTCP隐藏了很多套接字分配和绑定的细节2.QLEN:客户连接请求等待队列长度3.在循环中,使用accept从主套接字得到一个连接(accept完成三次握手过程)4.对于新的连接服务器调用过程TCPdaytimed进行处理5.处理完毕继续循环,再次调用accept阻塞关闭连接调用TCPdaytimed返回后,主程序关闭改连接的套接字调用close是从容关闭:TCP保证所有的数据可靠交付给客户(连接终止前收到确认)close不能立刻返回,调用将会阻塞连接终止和服务器的脆弱性1.连接终止问题①DAYTIME服务器知道何时应该终止连接②复杂客户服务器系统的应用,必须了解客户什么时候是最后一个请求,客户必须发送一个完成的信号2.允许客户控制连接时间有危险①误操作的客户可能导致服务器消耗掉套接字和TCP连接之类的资源②客户快速的重复的发出请求,可以把服务器的资源用光(拒绝服务攻击)小结1.循环的面向连接的服务器每处理一个连接循环一次①连接达到以前在accept阻塞②建立新的连接以后创建新套接字处理③处理完毕,关闭这个连接,返回accept阻塞2.DAYTIME服务①不需要客户的请求信息等待连接就响应②发送完响应,服务器主动关闭连接③每个连接只发送一个响应