• 【手机网络游戏 编程】C#异步socketAPI调用 处理数据的流程


    之前客户端在网络条件好的时候,运行没问题.但是有时候手机的网络不稳定,接受数据可能不稳定,导致接受数据错误,一直都不知道,原来是接受数据处理的不够好!

    现在更改过后的接受数据的逻辑如下:

        //接收
        public void Receive(int length, bool tag, byte[] head)
        {
            if (clientSocket != null && clientSocket.Connected)
            {
                StateObject stateObject = new StateObject(length, clientSocket, tag, head);
                clientSocket.BeginReceive(stateObject.sBuffer, 0, stateObject.sBuffer.Length, SocketFlags.None, new AsyncCallback(receiveCallback), stateObject);
            }
        }
    
        //接收回调
        private void receiveCallback(IAsyncResult asyncReceive)
        {
            try
            {
                //异步接收的结果
                StateObject stateObject = (StateObject)asyncReceive.AsyncState;
                
                if (stateObject.sSocket == null)
                {
                    m_CallReceive(false, Error_Socket.SOCKET_NULL, "", null, "");
                    return;
                }
                else if (!stateObject.sSocket.Connected)
                {
                    m_CallReceive(false, Error_Socket.SOCKET_UNCONNECT, "", null, "");
                    Debug.Log("连接断开");
                    return;
                }
                //接收标示
                if (stateObject.spkgTag)
                {
                    #region This_TIME_RECV_PKG_HEAD
                    int recv_this_time_length = stateObject.sSocket.EndReceive(asyncReceive);
                    //接收到的数据
                    byte[] m_recv_Buffer = new byte[recv_this_time_length];
                    ComClass.MemCpy(m_recv_Buffer, stateObject.sBuffer, 0, recv_this_time_length);
    
                    mypkg_head pkg_head_tmp = new mypkg_head();
                    pkg_head_tmp.unpacket(m_recv_Buffer);//解析数据包
    
                    //接收消息长度为10
                    if (pkg_head_tmp.length == 10 && recv_this_time_length>=10)
                    {
                        m_CallReceive(true, error_Socket, "", m_recv_Buffer, "");
                    }
                    else if(pkg_head_tmp.length>10 && recv_this_time_length>=10)
                    {
                        Receive(pkg_head_tmp.length - recv_this_time_length, false, m_recv_Buffer);
                        return;
                    }else{
                    Debug.LogError("######## ERROR PKG_HEAD ERROR [ "+recv_this_time_length+" bytes] #############");
                    }
                    #endregion
    
                }
                else//数据
                {
                    #region THIS_TIME_CONTINUE_RECV_DATA
                    int have_recv_length=stateObject.sheadBuffer.Length;
                    int recv_this_time_length = stateObject.sSocket.EndReceive(asyncReceive);
                    //接收到的数据
                    byte[] m_recv_Buffer = new byte[recv_this_time_length + have_recv_length];
                    //////m_recv_Buffer = ComClass.ConnectBytes(stateObject.sheadBuffer, stateObject.sBuffer);
                    ComClass.MemCpy(m_recv_Buffer, stateObject.sheadBuffer, 0, stateObject.sheadBuffer.Length);
                    ComClass.MemCpy(m_recv_Buffer, stateObject.sBuffer, stateObject.sheadBuffer.Length, recv_this_time_length);
    
                    mypkg_head pkg_head_tmp = new mypkg_head();
                    pkg_head_tmp.unpacket(m_recv_Buffer);//解析数据包
    
                    Debug.Log("[length="+pkg_head_tmp.length+"][type="+pkg_head_tmp.type+"][command="+pkg_head_tmp.command+"][uid="+pkg_head_tmp.uid+
                        "] 前面已经接受了"+have_recv_length+"个字节;本次接受"+recv_this_time_length+"个字节;  已经累计接受了"+m_recv_Buffer.Length+"个字节");
                    //sbuffer分配的大小 比实际接受到的小,那么就得继续接受完!!!
                    //##if(stateObject.sBuffer.Length!=recv_this_time_length && false){
                    //##    Debug.LogError("####################   ERROR:stateObject.sBuffer.Length["+stateObject.sBuffer.Length+
                    //##        "]!=recv_this_time_length["+recv_this_time_length+"]  ####################");
                    //##    return;
                    //##}
    
                    if(m_recv_Buffer.Length < pkg_head_tmp.length){
                        Debug.Log("## TOBE Continue:还需要接受"+(pkg_head_tmp.length-m_recv_Buffer.Length)+"个字节 ");
                        Receive(pkg_head_tmp.length - m_recv_Buffer.Length, false, m_recv_Buffer);
                        return ;
                    }else if(m_recv_Buffer.Length == pkg_head_tmp.length){
                        Debug.Log("## 刚刚好接受完一个包数据,进行处理...[pkg_head_tmp.length="+pkg_head_tmp.length+"]");
                        m_CallReceive(true, error_Socket, "", m_recv_Buffer, ""); 
                    }else{
                        Debug.LogError("========ERROR=================");
                        Debug.LogError("             多接受了"+(pkg_head_tmp.length-m_recv_Buffer.Length)+"个字节!!!!!!! ");
                        Debug.LogError("========ERROR=================");
                        return;
                    }
                    #endregion
                }
                //结束异步的数据读取之后,从新开始接收数据
                Receive(10, true, null);
            }
            catch (System.Exception ex)
            {
                if (null != m_CallReceive)
                {
                    m_CallReceive(false, Error_Socket.RECEIV_UNSUCCESS_UNKNOW, ex.ToString(), null, "");
                    Debug.Log(ex.ToString());
                }
            }
        }
    
        //定义Object
        private class StateObject
        {
            internal byte[] sBuffer;//本次接收到的实际数据
            internal Socket sSocket;//socket
            internal bool spkgTag;//包的标示
            internal byte[] sheadBuffer;//消息头的数据
            internal StateObject(int size, Socket sock, bool tag, byte[] data)
            {
                sheadBuffer = data;
                sBuffer = new byte[size];
                sSocket = sock;
                spkgTag = tag;
            }
        }

    最主要的还是 如果数据不够的话,要继续接受。以上代码 是公司框架之后的代码,是游戏代码的一部分,只供学习逻辑,不可以直接运行!

    这是我自己的逻辑。

    其实还有另外一种逻辑,那就是 使劲接受到一个比较大的缓冲区。接受的足够了,在处理,其他的继续接受。

  • 相关阅读:
    HashSet集合保证元素唯一性的原理 底层代码 ---有用
    集合(下) ---有用
    集合(上) Colection方法 并发修改异常
    Hive -- Hive面试题及答案sql语句 ---阿善有时间看
    hive面试题总结(2020最新版) hive优化方面 ---阿善重要
    hive面试题总结(2020最新版)
    Hive常见面试题1.0
    Hive面试题收集 ---阿善重要
    promise的三个缺点
    js中常见的高阶函数
  • 原文地址:https://www.cnblogs.com/ayanmw/p/3727419.html
Copyright © 2020-2023  润新知