zoukankan      html  css  js  c++  java
  • C++ 非阻塞套接字的使用 (2)

             继续话题——软件中的异步非阻塞通讯方式。

             由于软件基于MFC开发,所以实现异步通讯时使用了CAsyncSocket类。

             首先要了解CAsyncSocket异步机制,引用自

    http://blog.csdn.net/tianhai110/article/details/2115270

             由于CAsyncSocket采用的是异步非阻塞机制,所以你随时可以发包,也随时可能收到包。

    发送、接收函数都是异步非阻塞的,顷刻就能完成,所以收发交错进行着。也正因为如此,仅调用

    它们并不能保障发送或接收的完成。例如发送函数Send,调用它可能有3种结果:错误、部分完成、

    全部完成。其中错误又分两种情况:一种是由各种网络问题导致的失败,你需要马上决定是放弃本次操作,

    还是启用某种对策;另一种是“忙”,你实际上不用马上理睬。你需要调用GetLastError来判断是哪种情况,

    GetLastError返回WSAEWOULDBLOCK,代表“忙”,为什么当你Send得到WSAEWOULDBLOCK却

    不用理睬呢?因为CAsyncSocket会记得你的SendWSAEWOULDBLOCK了,待发送的数据会写入

    CAsyncSocket内部的发送缓冲区,并会在不忙的时候自动调用OnSend,发送内部缓冲区里的数据。

    同样,如果Send只完成了一部分,你也不需要理睬,尚未发送的数据同样会写入CAsyncSocket内部的

    发送缓冲区,并在不“忙”的时候自动调用OnSend完成发送。

             与OnSend协助Send完成工作一样,OnRecieve、OnConnect、OnAccept也会分别协助Recieve、

    Connect、Accept完成工作。这一切都通过消息机制完成。

             在你使用CAsyncSocket之前,必须调用AfxSocketInit初始化WinSock环境,而AfxSocketInit会

    创建一个隐藏的CSocketWnd对象,由于这个对象由Cwnd派生,因此它能够接收Windows消息。一方面它

    会接受各个CAsyncSocket的状态报告,另一方面它能捕捉系统发出的各种SOCKET事件。所以它能够成为

    高层CAsyncSocket对象与WinSock底层之间的桥梁:例如某CAsyncSocket在Send时WSAEWOULDBLOCK了,

    它就会发送一条消息给CSocketWnd作为报告,CSocketWnd会维护一个报告登记表,当它收到底层WinSock

    发出的空闲消息时,就会检索报告登记表,然后直接调用报告者的OnSend函数。所以前文所说的CAsyncSocket

    会自动调用OnXxx,实际上是不对的,真正的调用者是CSocketWnd——它是一个CWnd对象,运行在独立的线程中。

              以上是CAsyncSocket的原理,而具体代码如下(接收端):

              首先在头文件中声明继承自CAsyncSocket的类,并重写三个方法:

    #include <afxsock.h>
    
    class CMyAsyncSocket :
        public CAsyncSocket
    {
    public:
        CMyAsyncSocket(void);
        ~CMyAsyncSocket(void);
    
        virtual void OnClose(int nErrorCode);
        virtual void OnConnect(int nErrorCode);
        virtual void OnReceive(int nErrorCode);
    };

              在cpp文件中分别实现这三个方法:

    void CMyAsyncSocket::OnClose(int nErrorCode) 
    {
        if ( 0 == nErrorCode)
        {
            Close();
        }
        CAsyncSocket::OnClose(nErrorCode);
    }
    
    void CMyAsyncSocket::OnConnect(int nErrorCode) 
    {
        if (0 == nErrorCode)
        {
            //TODO:建立连接后的动作
        }
        CAsyncSocket::OnConnect(nErrorCode);
    }
    
    void CMyAsyncSocket::OnReceive(int nErrorCode) 
    {
        if (0 == nErrorCode)
        {
            //TODO:接受后的处理
            char szRcv[513] = "";
            int nRcved = Receive(szRcv,15);
        }
        CAsyncSocket::OnReceive(nErrorCode);
    }

               接下来,在需要通信的文件中就可以调用这个类:

        CMyAsyncSocket m_pClientSocket; 
    
        AfxSocketInit();           
        m_pClientSocket.Create();
        m_pClientSocket.Connect(_T("IP"),PORT);

              在使用过程中有三个地方需要注意:

        1.使用前进行AfxSocketInit()初始化;

             2.如果出现消息只能接受一次的现象,注意在Receive()后调用父类的OnReceive();

             3.在一个方法中,Connect()函数后面不能出现其他代码(这个尚不清楚原因)。

  • 相关阅读:
    希尔排序
    折半插入排序
    自学git心得-2
    读书笔记-1 《人月神话》
    USTCCourseCommunity 项目介绍
    自学git心得-1
    HDU 2006 求奇数的乘积
    HDU 2007 平方和与立方和
    HDU 2005 第几天?
    HDU 2004 成绩转换
  • 原文地址:https://www.cnblogs.com/libcan/p/4241361.html
Copyright © 2011-2022 走看看