【小松教你手游开发】【unity系统模块开发】unity网络层读写

在unity做强联网游戏的时候一般会选择用tcp来做通信(据说有一种udp的传输具有更高的效率),而接收信息的方法上一般会选择新建一个线程循环读取。

今天在我们项目上看到另外的一种方法。这里记录一下。

首先建立tcp连接

#using System.Net.Sockets;  

TcpClient tcpClient = new TcpClient();
tcpClient .BeginConnect(address,port,new AsyncCallback(this.OnConnect),result);  

可以看到这里用的是异步通信回调函数AsyncCallback

private void OnConnect(IAsyncResult ar)
{
    ConnectResult result = ar.AsyncState as ConnectRsult;
    try
    {
        result.client.EndConnect(ar);
        int size = HeaderLength;//定好的表头大小
        byte[] readBuf = new byte[size];
        result.client.GetStream().BeginRead(readBuf,0,size,new AsyncCallback(this.OnRead),new RecvIremObject(result.client,readBuf,size));
    }
    catch(System.Net.Sockets.SocketException e)
    {
    }
}  

上面是连接成功后的函数,连接成功后就可以断开连接并开始接受表头;同样是在异步通信回调函数内使用

private void OnRead(IAsyncResult ar)
{
    RecvItemObject item = (RecvItemObject)ar.AsyncState;
    try
    {
        Stream stram = item.client.GetStram();
        int readsize = stream.EndRead(ar);
        item.current =+= readsize;
        TotalReadSize += (uint)readsize;
        if(item.current < item.total)
        {
            item.client.GetStram().BeginRead(ite.bufs,item.current,item.total - item.current,new AsyncCallback(OnRead),item);
        }
        else
        {
            if(item.state == RecvItemObject.EndReadState.ReadHearder)
            {
                //上面就是读取信息逻辑,数据在item.bufs里,自己按需求解析
                //下面计算是否读完包头,下次应该读包还是包头
                if(true)
                {
                    item.client.GetStram().BeginRead(item.bufs,0,bufsSize,new AsyncCallback(this.OnRead),item);
                }
                else
                {
                    item.client.GetStram().BeginRead(item.bufs,0,dataLength,new AsyncCallback(this.OnRead),item);
                }  

            }
            else(item.state == RecvItemObject.EndReadState.ReadData)
            {
                //上面就是读取信息逻辑
                //下次应该读包头
                item.client.GetStram().BeginRead(item.bufs,0,bufsSize,new AsyncCallback(this.OnRead),item);
            }
        }  

    }
}  

可以看到,这种方式也就是一直通过调用异步加载函数AsyncCallback
来实现一直读取信息
而上面用的的BeginRead()函数的最后一个参数item是自己定义的一个数据类,函数的这个参数是用来下次异步回调的时候把上次的item传给下个回调

private class RecvItemObject
{
    public enum EReadState
    {
        ReadData,
        ReadHeader,
    }
    public byte[] bufs;
    public int total;
    public int current;
    public EReadState state;
    public TcpClient client;
    public NetworkStram networkStream;  

    public RecvItemObject(TcpClient client, byte[] bufs,int total)
    {
        this.client = client;
        this.bufs = bufs;
        this.total = total;
        current =0;
        state = EReadState.ReadHeader;  

    }
}  

而写数据呢,是在游戏的Update里发送,加一条发送信息就在队列里加一个,在Update里检测如果队列里有需要发送的数据就写数据

public void UpdateSend()
{
    //填写数据
     try
     {
        NetworkStream stream = tcpCLient.getStream();
        if(stream.CanWrite)
        {
            //pMsg数据Byte[]
            stream.BeginWtrite(pMsg,0,pMsg.Length,new AsycCallback(this.OnWrite),tcpCLient);
        }  

     }
    catch(SocketException e)
    {
    }
} 

在发送完了以后会跑到上面的异步回掉OnWrite里。在里面把流关闭写入

private void OnWrite(IAsyncResult ar)
{
    TcpClient client = (TcpClient)ar.AsyncState;
    try
    {
        client.GetStream().EndWrite(ar);
    }
    catch(SocketException e)
    {
    }
}  

原文地址:http://blog.51cto.com/13638120/2084958

时间: 2024-12-10 08:03:47

【小松教你手游开发】【unity系统模块开发】unity网络层读写的相关文章

【小松教你手游开发】【unity实用技能】角色头部跟随镜头旋转

这个在端游上比较场景,在角色展示的时候,当摄像头在角色身边上下左右旋转时,角色头部跟随镜头旋转.如天涯明月刀等. 这个在手游上比较少见,不过实现也没什么区别. 首先一般情况下,找到模型的头部节点,直接用lookAt指向camera就可以了,不过一般需求不会这么简单. 比如说,超过头部扭动极限,头部需要插值回到原始点:当镜头从外部回到极限内,需要插值回来.这时候lookat就没法使用. 更有情况,头部本身坐标系不在世界坐标轴上, 可能旋转了90多或者输出的prefab就是歪的等等,这些情况都没办法

【小松教你手游开发】【unity实用技能】根据上一个GameObject坐标生成的tips界面

开发游戏,特别是mmo手游的时候经常需要开发的一个需求是,点击某个装备,在它附近的位置生成一个tips界面,介绍装备功能和各种信息. 像上面红色框框里的这个. 这个主要的问题是 根据点击的GameObject对应生成这个详情界面时,详情界面位置需要合理摆放(不能显示不到,不能遮挡等) 基本的思路是, 首先找到GameObject的position, 把手机屏幕大概分成四个象限,知道这个GameObject大概在这个屏幕的哪个象限(左上,左下,右上,右下) 根据象限来判断详情界面应该在GameOb

【小松教你手游开发】【unity系统模块开发】热更

现在的手游项目如果没个热更新迭代根本跟不上, 特别是像我们项目做mmo的更是需要经常改动代码. 而现在的项目一般会选择用lua的方式实现热更新 不过我们项目由于历史原因没有使用,用的是另外一种方案 在项目里的所有GameObject都不挂脚本(NGUI脚本就通过代码的方式挂上),自己写的脚本都不继承Mono并打成dll,然后通过一个启动脚本去打开这些dll. 不过这样就有个问题,ios不能热更... 不管怎么样,先来讲讲这种方案要怎么做. 首先有两部分,一部分是打包,一部分是解包. 而包又分为资

【小松教你手游开发】【unity系统模块开发】Unity Assetbundle打包笔记

*最近项目更新了Unity5.5.2,顺便更新了项目的ui打包,也更新一下这边的笔记 首先打包分为两部分,一部分是打包成Assetbundle包,一部分是从Assetbundle包解包出来成为可用的资源. 首先说第一部分 打包 所有资源都可以打包,甚至不是资源(一些数据)也可以打包,只要你需要. 打包出来的东西都可以直接用,一个字体,一个Texture,一个Prefab,一个场景,都是一打出来成Assetbundle包就可以直接用,但是为什么大家还是要各自开发自己的打包流程呢? 最重要的原因就是

【小松教你手游开发】【系统模块开发】unity 数据储存到本地为二进制文件(聊天记录本地储存)

unity游戏开发中有很多需要把数据储存到本地,官方有好几个方式可以使用,下面简单介绍一下. 一.Stream::Write,Stream::WriteLine 这个方法是打开数据流就开始写字符串,可以指定长度写,也可以一行一行的写.具体参考http://blog.csdn.net/dingxiaowei2013/article/details/19084859和雨松大神的http://www.xuanyusong.com/archives/1069 这种方法最简单,一行一行的写,一行一行的读,

【小松教你手游开发】【unity实用技能】拓展函数(给系统代码添加可直接使用的接口)

拓展函数的意思是给一些没有源码的脚本添加上你自己写的接口并可以直接调用. using UnityEngine; using System.Collections; namespace ExtensionMethods { public static class MyExtensions { public static void SetLocalPositionX(this Transform transform, float x) { Vector3 newPosition = new Vect

【小松教你手游开发】【unity系统模块开发】Unity5.5.2UI打包AssetBundle

之前已经有几篇文章写打包AssetBundle,但毕竟没有实际在项目中写过都写的比较浅. 刚好最近项目更新Unity5.5.2就顺便由我来更新ui打包流程 这里就把这次的经验写一下 这里还是稍微解释一下打包的基本目的: 打包ui就是把你做的界面打包出来成assetbundle包,讲道理你就把每个界面打成bundle包在游戏中你就可以直接加载来用,但是这样子的话你的每个bundle包就会非常的大,为什么呢,是因为这样子每个界面的bundle包里都包含这个界面用到的字体,贴图atlas,textur

【小松教你手游开发】【系统模块开发】做一个3d旋转菜单

在unity做一个3d旋转菜单,像乱斗西游2的这种: 暂时有两种方法可以实现: 一.当做是2d界面,通过定义几个固定点的坐标.大小.透明度,还有每个点的panel depth大小,把数据存储下来,在手机滑动的过程中计算滑动划过的距离和这个panel大小的比值,乘以两个点之间的距离,获得坐标点移动的距离,通过改变x轴改变位置,同理改变大小和透明度. 这个方法我自己做2d游戏的时候实现过,做起来比较简单,没有什么可拓展性可言,并且会有很多限制,比如拖动过程中很难转变方向.要自己实现运动中的弹性(这里

【小松教你手游开发】【unity实用技能】InvalidOperationException: out of sync

在unity开发中出现这个bug. 在网上查了下是在迭代器中直接修改引起的.c#是不允许你在迭代器中直接修改. 改了一下确实解决. 原本是这样 [csharp] view plain copy public void Run() { foreach (var item in timerDict) { if (null != item.Value) { item.Value.Run(); } } } 改成这样: [csharp] view plain copy public void Run()