【编者按】网学网VC与C++类别频道为大家收集整理了“基于VC的网络寻呼软件“提供大家参考,希望对大家有所帮助!
客服咨询,网学网竭诚为您服务,本站永久域名:myeducs.cn |
.6服务器端的底层通讯类的设计 为了使能及时响应用户的请求,当用户很多时,仍然能够适应要求,我把侦听与发送数据的Socket分开,并分别都建立了多个实例, 也就是说,支持多个端口的侦听,发送数据使用的是多个端口,我只对侦听端口感兴趣,对发送数据的端口不感兴趣,因为,发送端口是多少都无所谓。 CRecvSocket和CsendSocket都是从CAsyncSocket类里继承而来,分别处理侦听请求各发送数据,在CServerSocket类里,定义了几个CRecvSocket和CSendSocket对象的实例,通过CServerSocket类对内部进行组织和管理,提供给上层的接口是CServerSocket,它隐藏了服务器底层通讯的细节及多线程发送数据的问题,提供给上一层一个统一的接口,CServerSocket类的使用,是先建立一个它的实例,再调用成员函数Create(),传入必要的参数,发送数据时,就调用其成员函数SendData,处理接受数据,在CRecvSocket类的OnReceive里处理,调用了一个名为ProcessRecvData的线程函数,用户在这个线程函数里写上具体的处理代码 算法描述: 发送一个数据,需要等待响应信息的回来,如果在规定时间内,还没有收到确认信息,则认为发送数据丢失,将重试FailReDoTime次,如果还是没有确认信息发送回来,则返回发送失败,否则,返回发送成功。 因为服务器是多线程的发送数据,有一个请求,就建立一个线程进行处理。我为每个发送socket设置一个是否忙的标志busy,当需要发送数据时,就选择一个空闲的sendsocket,设置为忙,然后发送数据,再设置回空闲,然后等待确认信息的回来。 SendData函数的实现算法,通过设置一个缓冲区长度为N,然后,为每一次数据进行统计,发一次,就加1,然后把发送数据中的This=count%N,且把缓冲区中第This个成员设为0,在发送端,就要数组中的第This个成员是否为1即可,在接受到的确认信息中,取出This项,再为缓冲区中第This项设为1,这样就可以快速且可靠的判断发送数据是否得到响应回来了。 侦听类结构: class CRecvSocket : public CAsyncSocket { private: char m_szResponseMsg[MaxResponseMsgLength]; 确认消息串 int m_szrLength; 确认消息串的长度 public: CRecvSocket(); virtual ~CRecvSocket(); public: BOOL Create(int nPort); 指定端口号,建立一个侦听Socket virtual void OnReceive(int nErrorCode); 处理接受数据 }; 发送数据的socket类结构 class CSendSocket : public CAsyncSocket { private: BYTE* pBuf; //指向CServerSocket的m_arBuf缓冲区,处理发送后是否收到确认信息的缓冲区 char m_szResponseMsg[20]; int m_szrLength; public: CSendSocket(BYTE*buf); virtual ~CSendSocket(); BOOL Create(); 建立一个发送的socket virtual void OnReceive(int nErrorCode); 处理发送数据后接受到的确认消息 }; 服务器的socket类 这个通讯类的SendData,当发送数据失败时,可以重发几次,次数可由用户来确定 class CServerSocket { public: void Close(); BOOL Create(int SendSockNum,CArray<DWORD,DWORD>&aPort,int TimeOut= TimeWaitForRes); //建立侦听Socket和发送Socket,aPort是侦听端口数组,TimeOut是设置发送超时时间 BOOL SendData(CData* pData,int FailReDoTimes=3); //数据函数,这个函数适合在线程里发送数据函数,而服务器的响应都是在工人线程里完成的,所以,很适合服务器的发送数据。成功返回真,不成功返回假 CServerSocket(); virtual ~CServerSocket(); private: CRecvSocket* m_apRecvSocket[ListenSocketNum]; 侦听Socket的指针数组 CSendSocket* m_apSendSocket[SendSocketNum]; 发送Socket的指针数组 int m_nRecvSocket; 侦听Socket的个数 int m_nSendSocket; 发送Socket的个数 BOOL m_abBusy[SendSocketNum]; 标志每个发送Socket是否处于忙的状态 BYTE m_arBuf[CheckBufLength]; 检查发送数据发回的确认的缓冲数组 DWORD m_nTotalSend; 保存从CserverSocket建立后,发送了多少次数据 DWORD m_nTimeOut; 发送数据的超时时间 }; §4.7客户端的底层通讯类的设计 与客户端上层的接口是CClientSocket类,它隐藏了服务器底层通讯的细节及多线程发送数据的问题,提供给上一层一个统一的接口,CClientSocket类的使用,是先建立一个它的实例,再调用成员函数Create()传入必要的参数,发送数据时,就调用其成员函数SendData,或SendDataInThread处理发送数据,在CRecvSocket类的OnReceive里处理,向父窗口发送一个WM_RECIEVE_MSG消息,并把接受到的数据作为参数传递给父窗口。两个函数的适应情况,SendData函数,适用于需要直接发送数据的场合,不需要回应。如果在线程里执行,则可由其返回值确定发送成功与否。而SendDataInThread是建立一个线程,在线程里调用SendData函数进行发送数据,通过向指定接受窗口发送消息来确定是否成功。 算法描述: 发送一个数据,需要等待响应信息的回来,如果在规定时间内,还没有收到确认信息,则认为发送数据丢失,将重试FailReDoTime次,如果还是没有确认信息发送回来,则返回发送失败,否则,返回发送成功。 因为客户端可以多线程的发送数据,有一个请求,就建立一个线程进行处理。我为每个发送socket设置一个是否忙的标志busy,当需要发送数据时,就选择一个空闲的sendsocket,设置为忙,然后发送数据,再设置回空闲,然后等待确认信息的回来。 SendData函数的实现算法,与服务器端是基本一样的原理,通过设置一个缓冲区长度为N,然后,为每一次数据进行统计,发一次,就加1,然后把发送数据中的This=count%N,且把缓冲区中第This个成员设为0,在发送端,就要数组中的第This个成员是否为1即可,在接受到的确认信息中,取出This项,再为缓冲区中第This项设为1,这样就可以快速且可靠的判断发送数据是否得到响应回来了。 因为在客户端,大部分数据,是在某个消息处理函数中执行的,所以,适用于服务器的SendData发送数据函数,在客户端,若是在消息处理函数中发送,函数返回值,将永远为FALSE,于是就添加了一个SendDataInThread函数,把发送数据的过程放在线程里执行,通过发消息的手段,来返回结果。在SendDataInThread函数中,调用SendData函数进行发送数据。 客户端通讯类的结构: class CClientSocket : public CAsyncSocket { public: CClientSocket(); virtual ~CClientSocket(); void SendDataInThread(CData* pData,CWnd*pWnd); // 在线程里发送数据,成功,或失败都会向指定窗口类发送一个WM_SENDINTHREAD_RES 的消息,参数WPARAM为发送数据的指针,参数LPARAM为1,则表示发送成功,0则表示发送失败 BOOL Create(int TimeOut=TimeWaitForRes); //建立SOCKET BOOL SendData(CData* pData,int FailReDoTimes=3); //发送数据成员函数,失败重试指定的FailReDoTimes次,成功返回真 CWnd* GetOwner(){return m_pWnd;}; //得到接受发来数据的处理窗口指针 void SetOwner(CWnd* pWnd){m_pWnd=pWnd;}; //设置接受发来数据的处理窗口指针 virtual void OnReceive(int nErrorCode);处理FD_READ网络事件 private: CWnd* m_pWnd; //接受发来数据的处理窗口指针 char m_szResponseMsg[MaxResponseMsgLength]; int m_szrLength; BOOL m_bBusy; //是否处理忙状态 BYTE m_arBuf[CheckBufLength];//检查确认信息的缓冲数组 DWORD m_nTotalSend; //从启动到现在为此,发送的数据总数 DWORD m_nTimeOut; //发送数据的超时时间 }; §4.8客户/服务器之间的通讯的数据类的设计 整个系统的所有的发送的数据,都包含在这几个类中了,当要发送一种数据,则先确定一个数据类,然后填入相应数据,再调用函数PackToBuf就可以把这些数据,存入szBuf的数组缓冲区中,num指示其长度,LoadFromBuf函数则是已知在缓冲区中数据,把各项的值,从缓冲区中提取出来。因为使用udp协议发送数据,sendto和recvfrom函数,只能处理串的发送和接受,所以,把数据压为串,和从串中恢复数据,是这些数据类所必须完成的功能。 算法描述: 定义的基类,提供了数据的一种统一的接口,其派生类再对其虚函数进行重载,实现相应的功能。在数据的打包过程中,对字符串的打包原理为:先存入串长度,再存入串。串的长度,采用的是2个字节的WORD类型,已经足够满足要求了。打包时,按照某一顺序,对其进行数据的存入串中,解开时,以相同的顺序进行还原即可。其中,类CModifyPersonPI的算法与其它类不大一样,因为它的成员中有一个位掩Mask成员,只有被选中的成员,才会打包入串。
|
本站发布的计算机毕业设计均是完整无错的全套作品,包含开题报告+程序+论文+源代码+翻译+答辩稿PPT |
本文选自计算机毕业设计http://myeducs.cn |