【手机网络游戏 编程】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, , 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调用 处理数据的流程的更多相关文章
- 【憩园】C#并发编程之异步编程(一)
写在前面 C#5.0中,对异步编程进行了一次革命性的重构,引入了async和await这两个关键字,使得开发人员在不需要深刻了解异步编程的底层原理,就可以写出十分优美而又代码量极少的代码.如果使用得当 ...
- Java网络编程中异步编程的理解
目录 前言 一.异步,同步,阻塞和非阻塞的理解 二.异步编程从用户层面和框架层面不同角度的理解 用户角度的理解 框架角度的理解 三.为什么使用异步 四.理解这些能在实际中的应用 六.困惑 参考文章 前 ...
- C#复习笔记(5)--C#5:简化的异步编程(异步编程的基础知识)
异步编程的基础知识 C#5推出的async和await关键字使异步编程从表面上来说变得简单了许多,我们只需要了解不多的知识就可以编写出有效的异步代码. 在介绍async和await之前,先介绍一些基础 ...
- Windows系统编程之异步I/O和完成端口
Windows系统编程之异步I/O和完成端口[作者]北极星2003[来源]看雪技术论坛(bbs.pediy.com) [时间]2006年7月1日 一. 同步I/O和异步I/O 在介绍这部分内容之前先 ...
- .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)
本文内容 异步编程类型 异步编程模型(APM) 参考资料 首先澄清,异步编程模式(Asynchronous Programming Patterns)与异步编程模型(Asynchronous Prog ...
- C#并发编程之异步编程2
C#并发编程之异步编程(二) 写在前面 前面一篇文章介绍了异步编程的基本内容,同时也简要说明了async和await的一些用法.本篇文章将对async和await这两个关键字进行深入探讨,研究其中 ...
- 从执行上下文角度重新理解.NET(Core)的多线程编程[1]:基于调用链的”参数”传递
线程是操作系统能够进行运算调度的最小单位,操作系统线程进一步被封装成托管的Thread对象,手工创建并管理Thread对象已经成为了所能做到的对线程最细粒度的控制了.后来我们有了ThreadPool, ...
- 进程内部异步事件调用组件Async-Event
项目坐标:https://github.com/cncduLee/async-event async-event 进程内部异步事件调用组件 解决什么问题: 加速服务处理效率.提供进程级别的事件发布和异 ...
- Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码)
原文:[原创]Matlab.NET混合编程技巧之--直接调用Matlab内置函数(附源码) 在我的上一篇文章[原创]Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了mat ...
随机推荐
- 【Ray Tracing in One Weekend 超详解】 光线追踪1-3
学完了插值,我们来学习在场景里面添加一个立体彩色球(三维插值) 按照惯例,先看效果: Chapter4: Adding a sphere 我们又一次面临图形学的主要任务. 我们需要再次回顾coord1 ...
- BZOJ.2462.[BeiJing2011]矩阵模板(二维Hash)
题目链接 序列上的Hash和前缀和差不多,二维Hash也和二维前缀和差不多了. 预处理大矩阵所有r*c的小矩阵hash值,再对询问的矩阵Hash. 类比于序列上\(s[r]-s[l-1]*pow[r- ...
- Node.js开源应用OSN发布初始V1.0版本-见面版本
Nodejs开源应用OSN初始版本V1.0发布,请参考本操作说明文档,有任何问题请留言 Nodejs开源应用OSN发布V1.0版本: OSChina收录地址: OSC收录地址:http://www.o ...
- Scrum:The Definition of Done —— 作业有没有写完呢?
Scrum:The Definition of Done -- 作业有没有写完呢?_苗得雨_新浪博客 http://blog.sina.com.cn/s/blog_59450ffc0102eiai.h ...
- JSP Servlet学习笔记——使用fileupload上传文件
关键代码如下: index.jsp <body> <center> <h3>文件上传</h3> <font color="red&quo ...
- Android学习笔记PreferenceFragment的使用
相信大家对Perference都比较熟悉了,也就是我们常说的偏好设置,首选项设置,可以保存一些数据,例如我们在上一次使用的时候的一些内容,希望在下一次启动后依然生效,而不需要再进行配置那么麻烦.一般这 ...
- SQL Server DATEDIFF() 函数(SQL计算时间差)
select * from task_list where 1=1 and datediff(dd,carateTime,getdate()) =0 定义和用法 DATED ...
- Xamarin adventures – Differences between iOS simulator and device
I had been happily coding an iOS app (targeting iPad) using Xamarin/VS.Net with everything working f ...
- 基于设备树的controller学习(1)
作者 彭东林pengdonglin137@163.com 平台 TQ2440Linux-4.10.17 概述 在设备树中我们经常见到诸如"#clock-cells"."# ...
- 自定义一个可以被序列化的泛型Dictionary<TKey,TValue>集合
Dictionary是一个键值类型的集合.它有点像数组,但Dictionary的键可以是任何类型,内部使用Hash Table存储键和值.本篇自定义一个类型安全的泛型Dictionary<TKe ...