10网络编程Word格式.docx

上传人:b****6 文档编号:20199237 上传时间:2023-01-17 格式:DOCX 页数:66 大小:221.61KB
下载 相关 举报
10网络编程Word格式.docx_第1页
第1页 / 共66页
10网络编程Word格式.docx_第2页
第2页 / 共66页
10网络编程Word格式.docx_第3页
第3页 / 共66页
10网络编程Word格式.docx_第4页
第4页 / 共66页
10网络编程Word格式.docx_第5页
第5页 / 共66页
点击查看更多>>
下载资源
资源描述

10网络编程Word格式.docx

《10网络编程Word格式.docx》由会员分享,可在线阅读,更多相关《10网络编程Word格式.docx(66页珍藏版)》请在冰豆网上搜索。

10网络编程Word格式.docx

数据报套接字(DatagramSockets)这种套接字所提供的通信方式并不可靠,即不能保证所传送的数据包一定合法,也不能保证数据包接收顺序与发送顺序完全一致,甚至数据包是否能够安全传送到目的端都不能保证。

由于系统提供的数据报套接字功能有限,因此我们必须在编程时充分考虑各种可能出现的异常情况,例如,如何控制数据包发送和接收顺序,如何保证数据包不被重复发送,另外如何数据包没有发送应该如何处理,这些工作就需要我们自已完成了。

更重要的是,在编写复杂的网络应用程序时,还必须考虑数据报的可靠性,因为如果只依赖于系统提供的支持,数据报套接字的可靠性是极差的,如果一个大型的网络通信应用程序经常出现崩溃,那么带来的损失将是不可估量的。

数据报套接字的主要用途是以广播方式发送数据,如记录型数据等。

流式套接字(StreamSockets)流式套接字的含义是数据发送后,需要按顺序而且不重复地由目的端接收。

这是一种可靠的数据传输方式,对于单个的数据报,以及完整的数据包,流式套接字都可以提供这种面向连接的数据传输。

流式套接字的使用要广泛得多,特别是对于大量的数据发送,或要求数据接收顺序时,都需要使用流式套接字。

在使用套接字进行网络编程时,有一个非常重要的概念即套接字的端口。

在Internet上每一个站点都有相应的数字化地址,我们称之为IP地址。

形式一般为NUM1.NUM2.NUM3.NUM4即用小数点分隔的4个数字,如198.53.145.3。

如果通过网络,有一个请求发到198.53.145.3对应的主机上,此请求将附带一个端口号信息,端口号是一个整数值,它标识了所请求的应用程序。

必须注意,有一些端口是系统为标准应用预留的,如端口80主要用于Web服务器监听客户应用程序如NetscapeNavigator浏览器发出的Web文档请求。

有一些应用程序在设计信息发送时并不是基于连接的,但这种发送方式是没有保障的,即我们不能确定数据确实发送出去了,也不能确定数据接收方的身份。

不过对于一些广播性质的信息发送,这种方式是比较适合的。

如典型的时间服务,时间服务器将当前时间发送给其所在范围内的每一台机器,至于对方是否接收,或对方接收到时间信息后作何响应,时间服务器都不关心。

我们在应用程序中所使用的套接字一般是基于连接的,即两个应用程序各自生成一个套接字,这样在两个对应的套接字之间就建立了一个连接,两个应用程序就是连接的两端。

如果已经建立了连接,意味着两端的应用程序可以在此通路上发送和接收信息了。

需要注意的是,在两个端点间建立连接会带来一定的时间延迟,一般来讲,延迟影响并不大,但对于实时性要求比较高的信息传送而言,就不太适合了,因此也可以考虑无连接的通信方式。

102MFCWinsock类类起初,在VisualC+中用套接字编程就意味着需要调用套接字动态连接库DLL中的相关API接口函数,即所有的功能的以函数为单位实现的。

提出面向对象概念之后,为了方便程序的编写和维护,需要自己建立套接字类,利用套接字类来封装有关套接字的特点和方法。

不过从VisualC+2.1版本以后,系统就已经提供了两个新的类来专门管理套接字,即CAsyncSocket及其子类CSocket。

在此之后使用套接字就有了更为抽象的接口,而且类似于套接字对象的初始化和撤销等工作是我们比较容易忽略的,使用套接字对象就可以帮助我们自动完成。

我们知道,Windows应用程序是异步实现的,在同一时间内可以同时完成多项任务,在老版本的Windows操作系统环境下,如果一个应用程序陷入了循环,或者由于某种原因处于挂起状态,那么其后果可能造成整个系统都陷入循环或挂起状态。

显然我们需要尽量克服这种现象发生,但是对于一个套接字发出的请求,通常是要求通过TCP/IP连接从而获得在Internet上另一个站点的信息,信息的接收过程往往需要很长的时间完成,此时我们认为用来发送或接收信息的套接字函数就被阻塞了。

对于这个问题,可以有3种解决方法:

创建线程创建一个线程,并将可能出现阻塞的套接字函数在此线程中完成,如果函数确实阻塞了,那么只会导致它所在的线程处于等待状态,而不会影响到整个应用程序。

这种方法是在线程思想得到发展之后出现的,最近才得到广泛使用。

轮询套接字状态在编写程序时,需要发出请求时,我们可以设置一个函数,其功能是一旦请求发送出去,就返回相应的确认信息,同时我们可以设置另一个函数,它的功能是与第一个函数相对应的,即不断地通过轮询套接字,来查看请求是否发送出去。

由于我们需要通过轮询的方式查看套接字状态,因此这种方法的效率是相当低的,需要浪费大量的处理时间进行检查,而不是完成具体的工作。

发送消息最后一种方法同样是通过设计函数实现对套接字状态的检查和管理,首先设置一个函数,其功能是请求一旦发送,就返回相应的确认信息,另外在请求结束时向Windows提交一个窗口消息。

目前,这种方法是最常用的,我们完全可以利用CAsyncSocket类完成这一工作。

例如,要向Internet上另一个站点发送一条串信息,这个过程要通过已建立连接的套接字完成,那么我们可以调用套接字的Send()函数实现,Send()函数本身并不一定能够发送具体数据,如果发现套接字并没有准备好,或者处于等待状态,Send()函数将立刻返回,如果套接字确实已经准备好,就会向套接字发送相关的消息,而套接字就会捕获这条消息,从而获得相就的数据,即前面所要求发送的串信息,这个过程虽然简单,但可以充分体现异步Winsock应用程序的原理。

虽然Winsock的原理很好理解,而且利用AppWizard我们就可以要求系统为我们实现一个最基本的Winsock应用程序。

但在实际应用中,使用Winsock编写网络应用程序,实现较为复杂的通信功能则是一项比较困难的工作。

在具体实现Winsock应用程序前,我们先来分析CAsyncSocket和CSocket类的属性和方法。

1021CAsyncSocketCAsyncSocket类的工作实际上就是封装了对异步Winsock调用的处理,其定义如下:

classCAsyncSocket:

publicCObjectDECLARE_DYNAMIC(CAsyncSocket);

private:

CAsyncSocket(constCAsyncSocket&

rSrc);

/noimplementationvoidoperator=(constCAsyncSocket&

/noimplementation/Constructionpublic:

CAsyncSocket();

BOOLCreate(UINTnSocketPort=0,intnSocketType=SOCK_STREAM,longlEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,LPCTSTRlpszSocketAddress=NULL);

/Attributespublic:

SOCKETm_hSocket;

operatorSOCKET()const;

BOOLAttach(SOCKEThSocket,longlEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE);

SOCKETDetach();

BOOLGetPeerName(CString&

rPeerAddress,UINT&

rPeerPort);

BOOLGetPeerName(SOCKADDR*lpSockAddr,int*lpSockAddrLen);

BOOLGetSockName(CString&

rSocketAddress,UINT&

rSocketPort);

BOOLGetSockName(SOCKADDR*lpSockAddr,int*lpSockAddrLen);

BOOLSetSockOpt(intnOptionName,constvoid*lpOptionValue,intnOptionLen,intnLevel=SOL_SOCKET);

BOOLGetSockOpt(intnOptionName,void*lpOptionValue,int*lpOptionLen,intnLevel=SOL_SOCKET);

staticCAsyncSocket*PASCALFromHandle(SOCKEThSocket);

staticintPASCALGetLastError();

/Operationspublic:

virtualBOOLAccept(CAsyncSocket&

rConnectedSocket,SOCKADDR*lpSockAddr=NULL,int*lpSockAddrLen=NULL);

BOOLBind(UINTnSocketPort,LPCTSTRlpszSocketAddress=NULL);

BOOLBind(constSOCKADDR*lpSockAddr,intnSockAddrLen);

virtualvoidClose();

BOOLConnect(LPCTSTRlpszHostAddress,UINTnHostPort);

BOOLConnect(constSOCKADDR*lpSockAddr,intnSockAddrLen);

BOOLIOCtl(longlCommand,DWORD*lpArgument);

BOOLListen(intnConnectionBacklog=5);

virtualintReceive(void*lpBuf,intnBufLen,intnFlags=0);

intReceiveFrom(void*lpBuf,intnBufLen,CString&

rSocketPort,intnFlags=0);

intReceiveFrom(void*lpBuf,intnBufLen,SOCKADDR*lpSockAddr,int*lpSockAddrLen,intnFlags=0);

enumreceives=0,sends=1,both=2;

BOOLShutDown(intnHow=sends);

virtualintSend(constvoid*lpBuf,intnBufLen,intnFlags=0);

intSendTo(constvoid*lpBuf,intnBufLen,UINTnHostPort,LPCTSTRlpszHostAddress=NULL,intnFlags=0);

intSendTo(constvoid*lpBuf,intnBufLen,constSOCKADDR*lpSockAddr,intnSockAddrLen,intnFlags=0);

BOOLAsyncSelect(longlEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE);

/Overridablecallbacksprotected:

virtualvoidOnReceive(intnErrorCode);

virtualvoidOnSend(intnErrorCode);

virtualvoidOnOutOfBandData(intnErrorCode);

virtualvoidOnAccept(intnErrorCode);

virtualvoidOnConnect(intnErrorCode);

virtualvoidOnClose(intnErrorCode);

/Implementationpublic:

virtualCAsyncSocket();

staticCAsyncSocket*PASCALLookupHandle(SOCKEThSocket,BOOLbDead=FALSE);

staticvoidPASCALAttachHandle(SOCKEThSocket,CAsyncSocket*pSocket,BOOLbDead=FALSE);

staticvoidPASCALDetachHandle(SOCKEThSocket,BOOLbDead=FALSE);

staticvoidPASCALKillSocket(SOCKEThSocket,CAsyncSocket*pSocket);

staticvoidPASCALDoCallBack(WPARAMwParam,LPARAMlParam);

BOOLSocket(intnSocketType=SOCK_STREAM,longlEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,intnProtocolType=0,intnAddressFormat=PF_INET);

#ifdef_DEBUGvirtualvoidAssertValid()const;

virtualvoidDump(CDumpContext&

dc)const;

#endifprotected:

friendclassCSocketWnd;

virtualBOOLConnectHelper(constSOCKADDR*lpSockAddr,intnSockAddrLen);

virtualintReceiveFromHelper(void*lpBuf,intnBufLen,SOCKADDR*lpSockAddr,int*lpSockAddrLen,intnFlags);

virtualintSendToHelper(constvoid*lpBuf,intnBufLen,constSOCKADDR*lpSockAddr,intnSockAddrLen,intnFlags);

CAsyncSocket类有一组非常有用的成员函数:

Accept函数在一个监听套接字端处理连接请求,即处理一个可能建立的连接,一旦建立连接,就写入相应的套接字地址信息。

这里参数rConnectedSocket为监听套接字,lpSockAddr即为套接字地址,其初始值为空,一旦连接建立,则将套接字实际地址通过lpSockAddr返回,另外lpSockAddrLen为套接字地址的长度。

AsyncSelect函数的作用是在套接字准备好之后,发出请求要求发送消息,消息的类型如表10.1所示:

表10.1消息类型类型值FD_READ0x01FD_WRITE0x02FD_OOB0x04FD_ACCEPT0x08FD_CONNECT0x10FD_CLOSE0x20BOOLAttach(SOCKEThSocket,longlEvent=FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE);

Attach函数的作用是将一个套接字句柄连接到一个CAsyncSocket对象实例上,即建立二者的关联,这样就可以实现与另一台计算机的连接了。

这里hSocket即为套接字句柄,其相关的消息类型与AsyncSelect相同。

Bind函数可以建立一个地址与套接字的关联,一般我们称之为绑定。

可以有两种调用形式,其一是提供套接字端口和地址,而且地址是以串作为参数类型的。

这种方法比较常用。

另一种是提供SOCKADDR结构类型的地址参数。

Close函数就是关闭套接字。

Connect函数可以建立套接字与远程地址和端口的连接,这个函数在WinSock应用程序中必须出现。

调用方式也有两种:

其一是提供套接字端口和地址,而且地址是以串作为参数类型的。

在调用CAsyncSocket构造函数之后,需要由Create函数实现具体的初始化工作。

Detach函数的作用是将上一次建立关联的套接字句柄断开,并返回此套接字句柄。

FromHandle函数参数将指定一个套接字句柄,其作用是返回与此套接字关联的CAsyncSocket对象指针staticintPASCALGetLastError();

GetLastError函数将返回套接字错误代码,在实际应用中需要在操作失败后调用此函数以查找错误原因。

指定套接字,调用GetPeerName函数就可以找到与之对应的远程套接字的IP地址和端口号。

远程套接字的IP地址和端口号可以分别由参数rPeerAddress和rPeerPort返回,也可以由指向SOCKADDR结构的参数lpSockAddr返回。

GetSockName与GetPeerName函数的作用类似,但更为简单一些,即指定套接字,则返回其IP地址和端口号。

IP地址和端口号可以分别由参数rPeerAddress和rPeerPort返回,也可以由指向SOCKADDR结构的参数lpSockAddr返回。

GetSockOpt函数和SetSockOpt函数的作用是对套接字状态的存取,对于SetSockOpt而言。

当前设置的套接字状态由参数lpOptionValue确定。

而对于GetSockOpt函数,可以由参数lpOptionValue得到套接字状态。

IOCtl的作用是设置套接字的模式,一般来说,主要有两种模式,即阻塞和非阻塞。

Listen函数的作用为监听,即构造一个套接字以查看是否需要建立连接。

OnAccept是一个需重载的回调函数,当一个套接字可能需要与另一端建立连接时,可以调用此函数处理相应的消息。

OnClose是一个需重载的回调函数,当一个套接字关闭时,可以调用此函数处理相应的消息。

OnConnect是一个需重载的回调函数,当一个套接字成功建立连接,或者连接失败时,可以调用此函数处理相应的消息。

OnOutOfBandData是一个需重载的回调函数,如果一些非常急需的数据已经准备好,就会发出相应的消息,这一类消息的处理需要由OnOutOfBandData完成。

OnReceive是一个需重载的回调函数,当一个套接字

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1