PartII基于LinuxMSWindows的Socket编程.ppt_第1页
PartII基于LinuxMSWindows的Socket编程.ppt_第2页
PartII基于LinuxMSWindows的Socket编程.ppt_第3页
PartII基于LinuxMSWindows的Socket编程.ppt_第4页
PartII基于LinuxMSWindows的Socket编程.ppt_第5页
已阅读5页,还剩181页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

PartII基于Linux/MSWindows的Socket编程,简单的时间日期程序客户端(IPv4),daytimetcpcli.c简介包含头文件创建TCPsocket指定服务器IP与端口与服务器建立连接读取并显示服务器应答终结程序,简单的Daytime客户端(IPv6),daytimetcpcli6.c服务器地址结构体sockaddr_in6if(sockfd=socket(AF_INET6,SOCK_STREAM,0)0)servaddr.sin6_family=AF_INET6;servaddr.sin6_port=htons(13);if(inet_pton(AF_INET6,argv1,大写字母开头lib/wrapsock.cUnixerrnoValue-错误码,简单Daytime服务器(IPv4)(迭代服务器),daytimetcpsrv1.c介绍创建TCPsocket绑定服务器端口将socket转换为监听socket接受客户端连接,作出应答终止连接,简单Daytime服务器(IPv6)(迭代服务器),daytimetcpsrvv6.c简介,结构体函数代码#definein_addr_tunsingedintstructsockaddr_inserv,Socket地址结构体(1),IPv4Socket地址结构体#include/linux/windows,所需要数据类型,注意,长度成员sin_len的设置和检查可选sin_family,sin_addr,sin_port,等三个成员为必须的in_addr_t为32位以上的无符号整数in_port_t为16位以上的整数sa_family_t可为任何类型的无符号整数无论IPv4地址的TCP端口还是UDP端口都必须存储为网络字节顺序serv.sin_addr指32位的IPV4地址,以in_addr结构存储,而serv.sin_addr.s_addr指相同的32位IPv4地址的in_addr_t形式,Socket地址结构(2),通用Socket地址结构#defineSAstructsockaddr,Socket地址结构(3),IPv6Socket地址结构(RFC3493),Socket地址结构传送过程,绑定(bind)连接(connect)传输(sendto),Socket地址结构接收过程,AcceptRecvfromGetsocknamegetpeername,字节顺序函数,Internet协议使用big-endian字节顺序-网络字节顺序,字节顺序转换函数,h(host)主机标准,n(network)网络标准,s(short)短整数标准,l(long)长整数标准.,Berkeley-derived函数ANSIC函数,地址转换(1),inet_aton将C语言字符串从strptr转换到32位网络字节顺序,存储到addrptrinet_addr作与同样的转换,但已废弃inet_ntoa转换32位网络顺序IPv4地址为C标准字符串,地址转换(2),family:AF_INET或AF_INET6inet_pton转换字符串指针strptr为网络格式,保存到addrptrinet_ntop转换网络数字(addrptr)为数字指针(strptr).len为目标的长度,防止内存溢出,地址转换(3),#defineINET_ADDRSTRLEN16/*forIPv4dotted-decimal*/#defineINET6_ADDRSTRLEN46/*forIPv6hexstring*/,例1,例2,协议无关函数,函数使用自己的静态缓存保存结果,返回值为缓存的指针注意函数使用的是静态缓存,使用时要保证线程安全。函数的实现(lib/sock_ntop.c),协议无关函数(1),协议无关函数(2),sock_bind_wildbindsthewildcardaddressandanephemeralporttoasocket.lib/sock_bind_wildsock_cmp_addrcomparestheaddressportionoftwosocketaddressstructures.lib/sock_cmp_addrsock_cmp_portcomparestheportnumberoftwosocketaddressstructures.sock_get_portreturnsjusttheportnumber,sock_ntop_hostconvertsjustthehostportionofasocketaddressstructuretopresentationformatsock_set_addrsetsjusttheaddressportionofasocketaddressstructuretothevaluepointedtobyptr,sock_set_portsetsjusttheportnumberofasocketaddressstructure.sock_set_wildsetstheaddressportionofasocketaddressstructuretothewildcard.,一些有用的函数,filedesisconsideredasasocketdescriptor.lib/readn.clib/writen.clib/readline.c,Windows中地址转换函数,INTWSAStringToAddress(LPTSTRAddressString,INTAddressFamily,LPWSAPROTOCOL_INFOlpProtocolInfo,LPSOCKADDRlpAddress,LPINTlpAddressLength);ParametersAddressStringin字符串形式的地址,需要有结束标记(0,NULL).AddressFamilyin地址协议簇.lpProtocolInfoin(可选)WSAPROTOCOL_INFO结构体,相关的协议提供者.如置为NULL,则为支持AddressFamily中协议簇的第一个提供者.lpAddressout单一的sockaddr结构体缓存.lpAddressLengthin,out输入地址缓存长度.返回结果的sockaddr结构体大小.如果缓存不足,则函数失败(产生WSAEFAULT错误),并将lpAddressLength修改为所需要的大小.ReturnValues成功则返回0.否则返回SOCKET_ERROR具体错误号可由WSAGetLastError获得,Similartoinet_pton()forlinux,Windows下地址转换函数,INTWSAAddressToString(LPSOCKADDRlpsaAddress,DWORDdwAddressLength,LPWSAPROTOCOL_INFOlpProtocolInfo,OUTLPTSTRlpszAddressString,INOUTLPDWORDlpdwAddressStringLength);ParameterslpsaAddressinsockaddr结构体,需要转换为string的对象.dwAddressLengthinsockaddr的长度,根据协议不同而不同.lpProtocolInfoin(可选)WSAPROTOCOL_INFO结构体,如果为空NULL,则请求为第一个支持lpsaAddress中相关协议的提供者.lpszAddressStringin用于接收转换好的字符串.lpdwAddressStringLengthin,out输入地址字符串的缓存长度,返回写入缓存字符串的实际长度,包含结束符号(0).如果缓存长度不足,函数返回错误WSAEFAULT并将lpdwAddressStringLength置为需要的长度.返回值成功则返回0,否则返回SOCKET_ERROR,具体错误号可由WSAGetLastError函数获得.,与UNIX中的inet_ntop()相似,基础TCPSocket编程,基本TCP客户端/服务器的Socket函数,send(),send(),recv(),recv(),closesocket(),closesocket(),recv(),socket()函数,要执行网络I/O(读写),必须首先调用socket函数,指定要使用的通信协议(TCPusingIPv4,UDPusingIPv6etc).,socket()函数,参数familyAF_INET:forIPv4AF_INET6:forIPv6typeSOCK_STREAM:TCP协议SOCK_DGRAM:UDP协议SOCK_RAW:基于IPv4/IPv6协议protocolIPPROTO_TCP:TCPIPPROTO_UDP:UDP编程时调用所返回的ID,或socket套接字(SOCKET),connect()函数,connect用于建立TCP客户端到服务器的连接sockfd为socket函数返回的IDsocket地址结构体servaddr必须包含服务器IP地址与端口号在使用TCP协议时,connect函数实现三次握手协议.函数一直到成功或失败时才返回值,bind函数,bind本地地址(IPv4orIPv6)提交给socketmyaddr为一个协议相关的地址服务器会在启动时绑定well-known端口,继.,TCP客户端或服务器不指定端口,内核在监听或连接时选择一个临时端口。对TCP客户端而言,通常让内核选择临时端口,除非应用程序需要保护某个端口,但TCP服务器很少这样做,服务器需要绑定到它们的well-known端口.,继.,继.,在IPv4/IPv6中wildcard(通配)地址使用INADDR_ANY/in6addr_any设置,listen函数,listen函数仅由TCP服务器调用,执行两个事务:当socket已创建时,假定它是激活的socket,也就是说,可以作为客户socket组织一个连接.listen函数转换一个未连接的socket为被动socket,指定内核应该接受相应的连接第二个参数则指定能够接受的最大连接数.,继.,通常此函数在socket与bind之后调用,必须在accept之前调用.对于指定的监听socket,内核维护两个队列:未完成的连接队列已完成的连接队列,TCP监听socket的两个队列,三次握手协议,accept函数,accept函数返回已完成队列中的下一个连接,如果队列为空,则进程执行Sleep等待,继.,参数cliaddr与addrlen用于返回客户端协议地址.Thefirstargumenttoacceptisthelisteningsocket(thedescriptorcreatedbysocketandthenusedasthefirstargumenttobothbindandlisten)Agivenservernormallycreatesonlyonelisteningsocket.Thekernelcreatesoneconnectedsocketforeachclientconnectionthatisaccepted.Whentheserverisfinishedservingagivenclient,theconnectedsocketisclosed.,继.,Thisfunctionreturnsuptothreevalues:anintegerreturncodethatiseitheranewsocketdescriptororanerrorindication,theprotocoladdressoftheclientprocess(throughthecliaddrpointer),thesizeofthisaddress(throughtheaddrlenpointer).Ifwearenotinterestedinhavingtheprotocoladdressoftheclientreturned,wesetbothcliaddrandaddrlentonullpointers.AnExample:intro/daytimetcpsrv1.c/daytimetcpcli.c,close函数,close用于关闭socket并终止TCP连接close()减少套接字参考数量(DRC)若DRC达到0,则TCP的四包连接终止序列被初始化.,fork函数,Fork()istheonlywayinUnixtocreateanewprocess.,继.,forkiscalledoncebutreturnstwice.Itreturnsonceinthecallingprocess(calledtheparent)withareturnvaluethatistheprocessIDofthenewlycreatedprocess(thechild).Italsoreturnsonceinthechild,withareturnvalueof0.Hence,thereturnvaluetellstheprocesswhetheritistheparentorthechild.,继.,Alldescriptorsopenintheparentbeforethecalltoforkaresharedwiththechildafterforkreturns.Wewillseethisfeatureusedbynetworkservers:Theparentcallsacceptandthencallsfork.Theconnectedsocketisthensharedbetweentheparentandchild.Normally,thechildthenreadsandwritestheconnectedsocketandtheparentclosestheconnectedsocket.,并发服务器(1),并发服务器(2),典型的并发服务器,getsockname与getpeername函数,返回SOCKET的本地协议地址(getsockname)或远程协议地址(getpeername).,续.,当连接成功返回TCP客户端后,使用getsockname返回内核指定结连接的本地IP与本地端口号.当使用0绑定端口时(让内核选择端口号),getsockname返回指定的本地端口号.在绑定了通配IP地址的TCP服务器,一旦与客户端建立了连接(accept返回成功值),就可以调用getsockname获得分配到连接上的本地IP地址.socket套接字参数必须是连接socket,而不是监听socket.,Winsock2头文件与库文件,Winsock2winsock2.hl需要连接库WS2_32.LIBmswsock.h微软开发的提供Winsock应用性能的扩展包,需要连接mswsock.lib,初始化Winsock,intWSAStartup(WORDwVersionRequested,LPWSADATAlpWSAData);wVersionRequested指定Winsock库的版本.高字节指定最小版本、,低字节指定主要版本。可以使用宏定义MAKEWORD(x,y)合并字节,其中x为高字节,y为低字节,以获得参数wVersionRWSACleanup(void);intWSAGetLastError(void);,Windows函数,SOCKETsocket(intfamily,inttype,intprotocol)typedefu_intSOCKETintbind(SOCKETs,conststructsockaddrFAR*name,intnamelen);intlisten(SOCKETs,intbacklog);SOCKETaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);intconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);intsend(SOCKETs,constcharFAR*buf,intlen,intflags);intrecv(SOCKETs,charFAR*buf,intlen,intflags);intclosesocket(SOCKETs);intgetpeername(SOCKETs,structsockaddrFAR*name,intFAR*namelen);intgetsockname(SOCKETs,structsockaddrFAR*name,intFAR*namelen);,TCP客户端/服务器实例,完整的TCP实例,回射服务器客户端从服务器读取并向服务器发送一行文本.服务器读取到客户端文本并回射给客户端.客户端读取到回射文本并显示,回射服务器的特点,一个正确的,但仍然是一个网络C/S结构应用的简单实例。所有实现C/S结构的基本步骤都在此例中展示。要扩展此实例,只需要修改服务器和客户端收到信息时的响应即可。,回射服务器:main()函数,tcpcliserv/tcpserv01.c创建socket,绑定众所周知的端口等待客户端连接完成并发服务器lib/str_echo.c读取客户端发送的信息并回射tcpcliserv/tcpli01.c创建socket,填充服务器地址连接到服务器lib/str_cli.c读取行,向服务器写入行读取回射行并显示,第二次作业,将concurrentechoserver移植到Windows下,要求如下:用select()/CreateProcess()函数构造concurrentserver用getsockname()/getpeername()获得本地地址和peer地址,然后显示IPv470-90IPv680-100协议独立90-10011月底或12月初检查,I/O复用,什么是I/O复用,告诉内核,我们希望得到I/O完成的通知条件,以便于网络读写同时还可以做别的事,I/O复用的应用场景,当客户端需要处理多个SOCKET(通常在输入设备与网络SOCKET交互)当TCP服务器需要同时处理监听与连接服务时当服务器同时需要处理TCP与UDP请求时,两种相异的输入操作,等等行数据准备好在socket的输入操作,首先包含等待数据到达网络的网络的步骤。当数据名到达时,拷贝数据到内核中。从内核拷贝数据进程,I/O模型,阻塞模型I/O非阻塞I/OI/O复用信号驱动I/O异步I/O,阻塞I/O模型,默认情况五,socket使用阻塞I/O,非阻塞I/O模型,I/O复用模型,使用一个select阻塞请求,信号驱动I/O模型,异步I/O模型,异步I/O与信号驱动I/O模型的区别,信号驱动I/O中,内核告诉我们I/O操作什么时候可以可以开始,但异步I/O中,内核告诉我们什么时候I/O操作被完成,五种I/O模型对比(1),继.,很明显前四中模型中,第一种,前四种的第二个步骤者一样:当调用recvfrom时数据被从内核拷贝到用户缓存,进程被阻塞。然而,异步I/O,handlesbothphasesandisdifferentfromthefirstfour.,同步I/O对比异步I/O,同步I/O产生进程请求,被阻塞直到I/O操作完成异步I/O操作不会引起进程操作阻塞使用以上定义,前四种I/O模型阻塞,非阻塞,I/O复用,信号驱动I/O均为同步,因为实际I/O操作(recvfrom)阻塞进程,只有异步I/O模型符合异步I/O的定义.,send和recv,intsend(ints,constvoid*msg,size_tlen,intflags);flags取值有:(windows只支持MSG_DONTROUTE,MSG_OOB,MSG_PEEK及其扩展)0:与write()无异MSG_DONTROUTE:告诉内核,目标主机在本地网络,不用查路由表MSG_DONTWAIT:将单个IO操作设置为非阻塞模式MSG_OOB:指明发送的是带外信息intrecv(ints,void*buf,size_tlen,intflags);flags取值有:0:常规操作,与read()相同MSG_DONTWAIT:将单个IO操作设置为非阻塞模式MSG_OOB:指明发送的是带外信息MSG_PEEK:可以查看可读的信息,在接收数据后不会将这些数据丢失MSG_WAITALL:通知内核直到读到请求的数据字节数时,才返回。,I/O复用模型,select函数,intselect(intmaxfdp1,fd_set*readset,fd_set*readset,fd_set*writeset,fd_set*exceptset,conststructtimeval*timeout)允许进程告诉内核等待多个套接字上的事务发生,当其中一个或多个事务发生,或超过时限时再唤醒进程.,三个集合参数,readset,writeset,exceptset,指定要做读、写或异常检查的套接字集合.套接字集合,通常为一个整数数组,其中每一个整数代表一个套接字(SOCKETID或文件ID,或其它输入输出设备ID)处理套接字集合(描述子)的几个宏:voidFD_ZERO(fd_set*fdset)清除集合中所有标志voidFD_SET(intfd,fd_set*fdset)将套接字放入集合voidFD_CLR(intfd,fd_set*fdset)将套接字从集合清除voidFD_ISSET(intfd,fd_set*fdset)判定套接字是否在集合中,例,Itisimportanttoinitializetheset,sinceunpredictableresultscanoccurifthesetisallocatedasanautomaticvariableandnotinitialized.如果我们对某个事务不感兴趣,则可将对应的readset,writeset,exceptset设置为null指针,时间参数,最后一个参数告诉内核需要等待的时间,结构体timeval指定要等待的秒数和毫秒structtimevallongtv_sec;/秒数longtv_usec;/毫秒数;,时间参数的三种选择,一直等待将timeout参数设置为空指针(NULL)等待固定的时间指定特定的时间(timeval)参数,在此时间范围内如果存在I/O准备好则返回,否则等超过这个时间后返回不等待将timeval参数设置为0,则检查完各socketID后立即返回。,Maxfdp1参数,指定要检查的套接字数值,应该为最大套接字加1.例如,当前存在套接字1,4,与5,则maxfdp1应该设置为6.在Windows下此参数无效,可以任意设置,Select函数的使用,select函数改变readset,writeset,与exceptset所指定的套接字集合。每次调用时都应该给定感兴趣的套接字集合值。在函数返回后,各fd_set集合标定已准备好的套接字,可使用FD_ISSET宏测试某某个套接字是否准备好。没有准备好的套接字的对应位会被从集合中清除.因此,每次调用select函数时都需要重新设置所有感兴趣的套接字。,返回值,Select函数返回所有准备好的套接字总数.如果等待超时且没有任何套接字准备好,则返回0.如果返回1,则意味着有错误发生。,Socket准备好读的条件,接收缓存的数据字节数大于等于当前接收缓存的最低标准线。读取连接的一半被关闭监听socket已经完成的连接数大于0(可以进行accept)存在未解决的socket错误,Socket准备好写的条件,发送缓存可用空间大于或等于当前发送缓存的最低标准线写连接的一半被关闭存在未解决的socket错误注意当错误发生时,select函数把它们标识为既可读又可写的.,str_cli函数(改进版),IfthepeerTCPsendsdataIfthepeerTCPsendsaFINIfthepeerTCPsendsanRSTselect/strcliselect01.c,批输入与缓存,使用批处理模式运行客户端Whenweredirecttheinputandoutput,however,theresultingoutputfileisalwayssmallerthantheinputfileThecauseoftheproblemisourhandlingofanEOFoninput:Thefunctionreturnstothemainfunction,whichthenterminates.Butinabatchmode,anEOFoninputdoesnotimplythatwehavefinishedreadingfromthesocket;theremightstillberequestsonthewaytotheserver,orrepliesonthewaybackfromtheserver.Whatweneedisawaytocloseone-halfoftheTCPconnection.Thatis,wewanttosendaFINtotheserver,tellingitwehavefinishedsendingdata,butleavethesocketdescriptoropenforreading.Thisisdonewiththeshutdownfunction,Shutdown函数,close()有两个局限close()减少套接字的引用数量,仅在引用数量为0时才关闭socket.使用shutdown可以初始化TCPs常规连接结束序列而无视引用数。close()结束读与写双向的数据操作。由于TCP连接是全双工的,有时我们需要告诉对方信息发送完毕时,对方仍然有数据要发送给我们。,调用shutdown关闭TCP连接的一半,howto参数.SHUT_RD:关闭连接的读功能。进程不能再调用连接的读函数。SHUT_WR:关闭连接的写功能。进程不能再调用连接的写函数SHUT_RDWR:同时关闭连接的读与写Thisisequivalenttocallingshutdowntwice:firstwithSHUT_RDandthenwithSHUT_WR,TCP回射服务器(改进版),使用select处理任意数量的客户请求,而不仅仅针对一个。,数据结构,Anarrayofintegersnamedclientthatcontainstheconnectedsocketdescriptorforeachclient.Allelementsinthisarrayareinitializedto1.tcpcliserv/tcpservselect01.c,性能对比,优势可以在同一线程中管理多个连接与I/O。劣势典型的FD_SETSIZE为1024,在Windows中默认为64,虽然可以扩充,但这个扩充会影响系统的可移植性。对于较大的FD_SETSIZE,select模型需要检查完所有的sockets后才返回,影响执行效率。,上机练习,以select函数完成回射服务器与客户端,即客户端循环输入消息、然后发射消息、再接收消息和显示;服务器等待接受连接或接收消息,有消息时发送回客户端并在服务器消息,select超时显示“select超时”。要求:分别用select的有限时间等待、无限时间等待完成,作业提交附服务器运行结果。,WindowsSocketI/O模型,SocketI/O模型对比,阻塞模型(与linux相似)I/O多路复用选择模型select(与linux相似)异步选择WSAAsyncSelect事件选择WSAEventSelect异步I/O模型OverlappedCompletionport,WSAAsyncSelect模型,WSAAsyncSelect模型,要使用WSAAsyncSelect模型,必须先创建一个窗口,比如使用CreateWindow函数,以(winproc)作为消息处理函数.intWSAAsyncSelect(SOCKETs,HWNDhWnd,unsignedintwMsg,longlEvent);,继,hWnd参数指定一个窗口,句柄相当于指针,指定接收消息的窗口或对话框。wMsg参数标志当网络事件发生时要接收的消息。这个消息会被自动发送到被hWnd指定的窗口。应和程序通常指定比WM_USER大的值以防止消息值与标准窗口消息产生混乱。lEvent参数的各位(bit)代表应用程序关心的事件组合。,以Windows消息接收事件通知,LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam);hWnd参数为调用窗口过程的窗口句柄。uMsg参数为需要处理的消息。你可以查询WSAAsyncSelect调用时所指定的消息。wParam参数标志发生网格事件的socket。如果一个窗口过程需要处理多个socket时这个参数很重要。lParam参数包含两个重要的信息片段参数的低字节标定已经发生的网络事件,WSAGETSELECTEVENT参数的高字节志发生的网络错误,WSAGETSELECTERROR例子程序(WSAAsyncSelect.txt),利弊分析,优势具有同时处理多个连接的能力,而不需要日常开销劣势即使应用程序不需要窗口时仍然得建立一个窗口以单一的窗口来为成千上万的套接字服务,可能成为性能瓶颈。,WSAEventSelect模型,WSAEventSelect模型,使用事件选择模型,网络事件使用事件句柄通知,而不是窗口消息。,事件通知,对每个套接字创建一个事件(保存句柄)WSAEVENTWSACreateEvent(void)将事件句柄与网络套接字、感兴趣的事件类型关联起来intWSAEventSelect(SOCKETs,WSAEVENThEventObject,longlNetworkEvents);hEventObject参数为事件句柄,由WSACreateEvent创建。lNetworkEvents参数代表感兴趣的网络事件类型,由FD_ACCEPT,FD_READ,FD_WRITE等值按位或运算组合而成。,事件状态与模式,WSAEventSelect的事件有两个操作状态和两个操作模式两个操作状态-有信号的和无信号的两个操作模式-手动重置和自动重置WSACreateEvent创建一个无信号和手动重置的事件当一个套接字事件发生时,自动触发与之相关的事件对象,事件的操作状态变为有信号的.由于事件状态默认是手动重置的,应用程序在接收到I/O请求后需要重置操作状态.BOOLWSAResetEvent(WSAEVENThEvent);事件对象使用完成后,应调用WSACloseEvent释放系统资源BOOLWSACloseEvent(WSAEVENThEvent);,等待网络事件,WSAWaitForMultipleEvents函数等待网络事件发生,当一个或多个事件对象被置为有信号或超时返回。DWORDWSAWaitForMultipleEvents(DWORDcEvents,constWSAEVENTFAR*lphEvents,BOOLfWaitAll,DWORDdwTimeout,BOOLfAlertable);,续,lphEvents与cEvents两个参数分别定义WSAEVENT对象数组和数组的大小。WSAWaitForMultipleEvents最多支持的事件数为WSA_MAXIMUM_WAIT_EVENTS即64个.,续,fWaitAll参数指定WSAWaitForMultipleEvents是否要等待所有事件数组中的事件发生,如果为TRUE,则需要lphEvents数组中所有事件都变为有信号才返回,否则一旦有一个变为有信号就返回。,续,dwTimeout参数指定WSAWaitForMultipleEvents要等待事件发生的时间(毫秒数)。如果dwTimeout为0,则函数检查完所有事件后立即返回。如果在限定时间没有事件发生则WSAWaitForMultipleEvents返回WSA_WAIT_TIMEOUT.如果dwsTimeout被设置为WSA_INFINITE,则函数等到指定的网络信号发生才返回。,避免资源浪费,只要有一个事件发生信号和处理,数组中的其它所有事件都应该被检查。可以使用WSAWaitForMultipleEvents完成事件检查,(数组中只设置一个事件元素,将dwTimeOut设置为0).,续,当WSAWaitForMultipleEvents接收到网络事件通知时,返回一个表明引起函数返回的事件的值。如果要参考事件数组中的事件,应该使用WSAWaitForMultipleEvents的返回值减去WSA_WAIT_EVENT_0.例如:Index=WSAWaitForMultipleEvents(,EventArray,);MyEvent=EventArrayIndex-WSA_WAIT_EVENT_0;,续,如果发生了网络事件,可以使用WSAEnumNetworkEvents检查发生的具体网络事件intWSAEnumNetworkEvents(SOCKETs,WSAEVENThEventObject,LPWSANETWORKEVENTSlpNetworkEvents);,MyEvent,续,hEventObject为可选参数,代表相关事件对象联系的句柄。最后一个参数lpNetworkEvents,WSANETWORKEVENTS结构体变量的指针,用于检索与套接字相关的网络事件类型typedefstruct_WSANETWORKEVENTSlonglNetworkEvents;intiErrorCodeFD_MAX_EVENTS;WSANETWORKEVENTS,FAR*LPWSANETWORKEVENTS;,续,lNetworkEvents参数为套接字上已经发生网络事件的类型。iErrorCode参数为发生错误的数组,错误代码与lNetworkEvents中的事件相关联对各网络事件分别有一个名字相似的事件索引在事件名后加上“_BIT”。例如:对FD_READ事件类型,在iErrorCode中的索引被命名为FD_READ_BIT.if(NetworkEvents.lNetworkEvents,利弊分析,优势无需窗口环境不足同时只能处理最多64个连接,重叠I/O模型,第三次作业,利用Overlapped模型编写回射服务器,Winsock扩展函数,WSASendWSASendToWSARecvWSARecvFrom,如何使用重叠I/O模式,要使用重叠I/O模型,各IO函数都要加上一个WSAOVERLAPPED结构体参数。当这些函数使用了WSAOVERLAPPED结构体参数后,它们立即返回忽略socket模式。重叠IO模式基于WSAOVERLAPPED结构体处理I/O请求的完成。有两种基本的方法管理重叠IO请求的完成:事件对象通知完成管道(例程),WSAOVERLAPPED结构,typedefstructtagWSAOVERLAPPEDDWORDInternal;DWORDInternalHigh;DWORDOffset;DWORDOffsetHigh;WSAEVENThEvent;WSAOVERLAPPED,FAR*LPWSAOVERLAPPED;,Internal保留的属性,由重叠I/O实现的实体内部使用的。对于使用类文件方式创建套接口的传输服务提供者,这一属性是被底层的操作系统使用的;对于其他的传输服务提供者(那些创建伪句柄的),可以视需要使用这个属性。InternalHigh保留属性,由重叠I/O实现的实体内部使用。对于使用类文件方式创建套接口的传输服务提供者,这一属性被底层的操作系统使用;对于其他的传输服务提供者(那些创建伪句柄的),可以视需要使用这个域。Offset由于套接口没有文件偏移量的概念,应用程序可以视需要使用这个属性。OffsetHigh由于套接口没有文件偏移量的概念,应用程序可以视需要使用这个属性。hEvent如果一个重叠的I/O操作在被调用时没有使用I/O操作完成例程(lpCompletionRoutine为空指针),那么这个域必须包含一个有效的WSAEVENT对象的句柄,否则(lpCompletionRoutine不为空指针),应用程序可以视需要使用这个域。,基于事件通知模式使用重叠I/O,当重叠I/O请求完成时,应用程序可以检索重叠结果.当请求完成后,在事件通知方法中,Winsock内核会修改与WSAOVERLAPPED对象相关联事件对象的状态为有信号的。可以使用WSAWaitForMultipleEvents检查事件以获得重叠I/O的完成状态,续,一旦检查到有重叠请求完成,则需要使用以下函数检查重叠请求的成功或失败:BOOLWSAGetOverlappedResult(SOCKETs,LPWSAOVERLAPPEDlpOverlapped,LPDWORDlpcbTransfer,BOOLfWait,LPDWORDlpdwFlags);,续,参数s标志开始重叠操作的套接字.参数lpOverlapped指向开始重叠操作时所指定的WSAOVERLAPPED结构体参数lpcbTransfer指向一个用于接收重叠操作所读写的字节数的DWORD变量.参数fWait决定函数是否要等待一个时间段,如果设为TRUE,则函数调用要等到操作完成才返回,否则,函数返回FALSE,并引起错误WSA_IO_INCOMPLETE.由于使用了重叠完成,这个参数无效。参数lpdwFlags指向一个用于接收是否由WSARecv或WSARecvFrom产生了重叠调用的DWORD参数,续,如果WSAGetOverlappedResult函数执行成功,返回值为TRUE.这意味着你的重叠操作已经成功完成,并且lpcbTransfer的内容已经被更新,编程步骤,创建一个套接字并开始监听端口,等待连接进入。accept进入的连接。为进入的连接创建WSAOVERLAPPED结构体,并为结构体指定事件(event)对象句柄。同时将事件句柄加入到用于WSAWaitForMultipleEvents函数的数组中。通过指定WSAOVERLAPPED参数发送一个异步WSARecv请求。调用WSAWaitForMultipleEvents等待有与重叠请求相关的事件变为有信号。使用WSAGetOverlappedResult检查重叠请求的返回信息.使用WSAResetEvent重置事件状态。发送另一个重叠WSARecv请求。重复步骤58.,intWSARecv(SOCKETs,/当然是投递这个操作的套接字LPWSABUFlpBuffers,/接收缓冲区,与Recv函数不同/这里需要一个由WSABUF结构构成的数组DWORDdwBufferCount,/数组中WSABUF结构的数量LPDWORDlpNumberOfBytesRecvd,/如果接收操作立即完成,这里会返回函数调用所接收到的字节数LPDWORDlpFlags,/用于接收返回的标志等LPWSAOVERLAPPEDlpOverlapped,/“绑定”的重叠结构LPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutine/完成例程中将会用到的参数,我们这里设置为NULL);,完成管道(例程),完成管道是执行重叠I/O请求时所指定的函数,当I/O请求完成时系统会自动调用这个函数(即所谓的回调函数)完成管道的主要作用是在完成I/O请求后在调用者线程中提供服务(注意调用线程并不知道I/O完成时间),续,要对重叠I/O请求使用完成管道,应用程序必须指定一个完成管道函数与一个WSAOVERLAPPED结构体.voidCALLBACKCompletionROUTINE(DWORDdwError,DWORDcbTransferred,LPWSAOVERLAPPEDlpOverlapped,DWORDdwFlags);,续,参数dwError指定由lpOverlapped规定的重叠操作的完成状态。参数cbTransferred指定重叠操作中传输的字节数参数lpOverlapped与最初调用I/O操作时传入的WSAOVERLAPPED结构体相同.参数dwFlags返回任何相应I/O操作可能返回的标志(如WSARecv的返回).,续,使用WSAWaitForMultipleEvents函数把你的线程设置为可警告等待状态或使用sleepEx函数将你的线程设置为可警告等待状态.如果调用线程一直忙并且不是可警告等待状态,则不会有完成管道被调用。,续,WSAWaitForMultipleEvents函数被设计在重叠I/O请求中同时用于设置进程与线程的可警告等待状态,条件是参数fAlertable设置为TRUE.当重叠I/O请求完成时,函数的返回值为WSA_IO_COMPLETE而不是事件句柄数组的下标.,续,除了不需要事件对象数组外,SleepEx函数提供与WSAWaitForMultipleEvents同样的行为.DWORDSleepEx(DWORDdwMilliseconds,BOOLbAlertable);,Cont.,如果dwMilliseconds设置为INFINITE,SleepEx无限期地等待.参数bAlertable决定完成管道如何执行.如果bAlertable设计为FALSE,并且I/O完成回调发生,则I/O完成函数直到dwMilliseconds指定的时间过去才执行并返回。如果这个参数设置TRUE,则完成管道立即执行并且SleepEx函数返回WAIT_IO_COMPLETE.,编程步骤,创建套接字并开始监听端口,等待连接.接受到达的连接.为接受的连接创建一个WSAOVERLAPPED结构体.用创建的WSAOVERLAPPED结构体作为参数发送一个异步WSARecv请求,支持完成管道.调用WSAWaitForMultipleEvents,其中fAlertable设置为TRUE,等待重叠请求完成.当重叠请求完成时,完成管道自动执行并且WSAWaitForMultipleEvents产生WSA_IO_COMPLETE消息.在完成管道(例程)内,发送另一个重叠WSARecv请求.验证WSAWaitForMultipleEvents是否产生WSA_IO_COMPLETE消息.重复第5、6两个步骤.,完成端口模型,优势,在所有IO模型中,完成端口模型提供最佳的可扩展性。完成端口模型很适合用于处理成百上千的套接字(网络连接)。,创建Windows完成端口对象,要使用完成端口模型,首先需要创建一个完成端口I/O对象,用于管理任意数量

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论