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

时间:2022-06-25 09:23:28

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

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

    //接收
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, , 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, , 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 == && recv_this_time_length>=)
{
m_CallReceive(true, error_Socket, "", m_recv_Buffer, "");
}
else if(pkg_head_tmp.length> && recv_this_time_length>=)
{
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, , 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(, 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;
}
}

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

这是我自己的逻辑。

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

【手机网络游戏 编程】C#异步socketAPI调用 处理数据的流程的更多相关文章

  1. 【憩园】C&num;并发编程之异步编程&lpar;一&rpar;

    写在前面 C#5.0中,对异步编程进行了一次革命性的重构,引入了async和await这两个关键字,使得开发人员在不需要深刻了解异步编程的底层原理,就可以写出十分优美而又代码量极少的代码.如果使用得当 ...

  2. Java网络编程中异步编程的理解

    目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...

  3. C&num;复习笔记(5)--C&num;5:简化的异步编程(异步编程的基础知识)

    异步编程的基础知识 C#5推出的async和await关键字使异步编程从表面上来说变得简单了许多,我们只需要了解不多的知识就可以编写出有效的异步代码. 在介绍async和await之前,先介绍一些基础 ...

  4. Windows系统编程之异步I&sol;O和完成端口

    Windows系统编程之异步I/O和完成端口[作者]北极星2003[来源]看雪技术论坛(bbs.pediy.com) [时间]2006年7月1日 一.  同步I/O和异步I/O 在介绍这部分内容之前先 ...

  5. &period;NET &ldquo&semi;底层&rdquo&semi;异步编程模式&mdash&semi;&mdash&semi;异步编程模型(Asynchronous Programming Model,APM)

    本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...

  6. C&num;并发编程之异步编程2

    C#并发编程之异步编程(二)   写在前面 前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法.本篇文章将对async和await这两个关键字进行深入探讨,研究其中 ...

  7. 从执行上下文角度重新理解&period;NET&lpar;Core&rpar;的多线程编程&lbrack;1&rsqb;:基于调用链的&rdquo&semi;参数&rdquo&semi;传递

    线程是操作系统能够进行运算调度的最小单位,操作系统线程进一步被封装成托管的Thread对象,手工创建并管理Thread对象已经成为了所能做到的对线程最细粒度的控制了.后来我们有了ThreadPool, ...

  8. 进程内部异步事件调用组件Async-Event

    项目坐标:https://github.com/cncduLee/async-event async-event 进程内部异步事件调用组件 解决什么问题: 加速服务处理效率.提供进程级别的事件发布和异 ...

  9. Matlab&period;NET混合编程技巧之——直接调用Matlab内置函数&lpar;附源码&rpar;

    原文:[原创]Matlab.NET混合编程技巧之--直接调用Matlab内置函数(附源码) 在我的上一篇文章[原创]Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了mat ...

随机推荐

  1. P 1080 Human Gene Functions

    大概作了一周,终于A了 类似于求最长公共子序列,稍有变形 当前序列 ch1 中字符为 a,序列 ch2 中字符为 b 则有 3 种配对方式: 1. a 与 b 2. a 与 - 3. - 与 b 动态 ...

  2. &lbrack;转&rsqb;省市二级联动(纯js实现)

    转至:http://www.jb51.net/article/41556.htm 实现原理: set_city("省名称",市select对象); 判断市select对象是否为空, ...

  3. Flask&lowbar;SqlAlchemy 1215&comma; &&num;39&semi;Cannot add f oreign key constraint&&num;39&semi;

    Flask_SqlAlchemy 1215, 'Cannot add f oreign key constraint'报错 sqlalchemy.exc.IntegrityError: (pymysq ...

  4. Leetcode:Repeated DNA Sequences详细题解

    题目 All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: " ...

  5. 多线程中lock用法的经典实例

    多线程中lock用法的经典实例 一.Lock定义     lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断.它可以把一段代码定义为互斥段(critical section),互斥段在一 ...

  6. Andorid第三方库

    博客: http://blog.csdn.net/codywangziham01/article/details/11818559#t8 RoboGuice: http://www.importnew ...

  7. VisionPro笔记(1)&colon;动态创建控件

     VisionPro学习笔记(1):动态创建控件 有的时候可能需要在程序中动态创建控件,VisionPro实例中提供了一例动态创建Blob控件的方法.当然,动态创建过多的控件会极大的消耗系统的资源,建 ...

  8. Linux kernel 4&period;9及以上开启TCP BBR拥塞算法

    Linux kernel 4.9及以上开启TCP BBR拥塞算法 BBR 目的是要尽量跑满带宽, 并且尽量不要有排队的情况, 效果并不比速锐差 Linux kernel 4.9+ 已支持 tcp_bb ...

  9. LeetCode算法题-Construct String from Binary Tree(Java实现)

    这是悦乐书的第273次更新,第288篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第141题(顺位题号是606).构造一个字符串,该字符串由二叉树中的括号和整数组成,并具 ...

  10. Netty精粹之玩转NIO缓冲区

    摘要: 在JAVA NIO相关的组件中,ByteBuffer是除了Selector.Channel之外的另一个很重要的组件,它是直接和Channel打交道的缓冲区,通常场景或是从ByteBuffer写 ...