Unity3D socket

来源:互联网 发布:张国荣爱情知乎 编辑:程序博客网 时间:2024/06/05 05:33

1年前的unity3D项目里面之封装了引擎层。完全没涉及到服务器收发。
最近继续深入u3d了。打算弄个框架。自然这个socket要我自己写了。花了1天的时间大概写好了。自己写了一个服务器一个客户端测了一下。
还不错。哈哈哈。
废话不说上代码.

使用双线程收发。这里有个取巧。
我在每帧更新之前。在主线程调用收线程的数据。
在每帧更新之后。在主线程发送数据到发线程。

这样我收和发的过程中不用锁。哈哈。完全不影响主线程。

虽然我是为客户端写的。但是还是考虑了极限情况。比如一次收到太多消息。导致一个缓冲区不够。我用一个链表后背缓冲区持续不断的收。
一次性做成包。主线程去拿。基本上可以当服务器用了。客户端可不会有这么恶心的情况。导致64k缓冲区都不够,那只能是服务器
主程有点二了。

一样的还是不能在收发线程里面做任何有关u3DAPI的调用。这二的。。

上类

netrecevice

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Xml.Xsl;
using System.IO;
using System.Threading;
namespace Lusuo
{
    public class NetRecevice : NetBase
    {
        public NetRecevice(Socket sock,uint uSize)
            : base("recevice", sock, uSize)
        {
            m_stream = new LusuoStream(new byte[uSize]);
        }

        public override void Stop()
        {
            base.Stop();
            m_stream.Close();
            for (int i = 0; i < m_listBackStream.Count; i ++ )
            {
                m_listBackStream[i].Close();
            }
        }

        public override void SubWork()
        {
            if (!m_socket.Connected)
            {
                //接收线程不能等待。因为没人去激活它
                Thread.Sleep(15);
                return;
            }
            ReceiveMessage();
            //接收完了。转换成消息等待前台拿
            GetReceviceToMsg();
            //接受完了休息指定帧数默认60帧
            Thread.Sleep(15);
        }
        //
        private void ReceiveMessage()
        {
            LusuoStream stream = __ReceviceMessage(ref m_stream);
            while (null != stream)
            {
                stream = __ReceviceMessage(ref stream);
            }
            m_stream.Reset();
        }

        private LusuoStream __ReceviceMessage(ref LusuoStream lf)
        {
            //先用基本缓冲读一次
            int iLen = 0;
            try
            {
                iLen = m_socket.Receive(lf.GetBuffer(), (int)m_uBufferSize, SocketFlags.None);
                if (iLen <= 0)
                {
                    return null;
                }
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
           
           
            //说明都读不完
            if (iLen >= m_uBufferSize)
            {
                __GenMsg();
                //还没有读完
                //用新的流继续读
                //把没有读完的数据写过来
                LusuoStream back = new LusuoStream(new byte[m_uBufferSize]);
                byte[] lastbyte = new byte[lf.GetRest()];
                lf.Read(ref lastbyte, lf.GetRest());
                back.Write(ref lastbyte, lastbyte.Length);
                //以后可以利用这个优化
                m_listBackStream.Add(back);
                return back;
            }
            else
            {
                //基本缓冲可以读完
                while (iLen > lf.GetOffset())
                {
                    if (-2 == __GenMsg(ref lf))
                    {
                        //断开因为有消息不认识了。说明客户端有问题了
                        //Stop();
                    }
                }
                return null;
            }
        }

        private void __GenMsg()
        {
            //int iMinSize = StringHelper.s_IntSize + StringHelper.s_ShortSize;
            //基本流读完了
            while (__GenMsg(ref m_stream) != -1) { }
        }

        private int __GenMsg(ref LusuoStream lf)
        {
            //如果不够读出一份完整数据。回读
            int iMinSize = StringHelper.s_IntSize + StringHelper.s_ShortSize;
            if (m_uBufferSize - lf.GetOffset() < iMinSize)
            {
                return -1;
            }
            uint uID        = 0;
            ushort uLen  = 0;
            lf.ReadUInt(ref uID);
            lf.ReadUShort(ref uLen);
            //如果不够读一次了
            if (m_uBufferSize - (ushort)lf.GetOffset() < uLen)
            {
                //返回
                lf.Seek(lf.GetOffset() - iMinSize);
                return -1;
            }
            //
            NetManager netMgr =
                        (NetManager)SingletonManager.GetSingletonManager().GetSingleton(ref Singleton.s_NetMessage);
            NetMessage msg = netMgr.CreateNetMessage(uID);
            if(null == msg)
            {
                Console.WriteLine("未知的消息" + uID.ToString());
                //客户端被修改
                return -2;
            }
            msg.m_uDataLenght = uLen;
            msg.FromByte(ref lf);
            m_listDelegates.Add(msg);
            return (int)m_uBufferSize - lf.GetOffset();
        }

        //得到接收的消息
        private void GetReceviceToMsg()
        {
            m_Lock.WaitOne();
            foreach (NetMessage msg in m_listDelegates)
            {
                m_listMsg.Add(msg);
            }
            m_listDelegates.Clear();
            m_Lock.ReleaseMutex();
            //新申请的内存用完了。
            for (int i = 0; i < m_listBackStream.Count; i++)
            {
                m_listBackStream[i].Close();
            }
            m_listBackStream.Clear();
        }

        public void GetReceviceMsg(ref List<NetMessage> listMsg)
        {
            if (m_listMsg.Count == 0)
            {
                return;
            }
            m_Lock.WaitOne();
            foreach (NetMessage msg in m_listMsg)
            {
                listMsg.Add(msg);
            }
            m_listMsg.Clear();
            m_Lock.ReleaseMutex();
        }

        protected LusuoStream m_stream = null;
        protected List<LusuoStream> m_listBackStream = new List<LusuoStream>();
    }

netsend

public class NetSend : NetBase
    {
        public NetSend(Socket sock, uint uSize)
            : base("send", sock, uSize)
        {
            m_stream = new LusuoStream(new byte[uSize]);
        }

        public override void Stop()
        {
            base.Stop();
            m_stream.Close();
        }

        public override void SubWork()
        {
            if (!m_socket.Connected)
            {
                Suspend();
                return;
            }
            //如果还没有建立连接试着建立连接
           
            int iMsgNums = MakeBuffer(ref m_stream);
            if (iMsgNums > 0)
            {
                try
                {
                    int iLen = m_socket.Send(m_stream.GetBuffer(), 0, m_stream.GetOffset(), SocketFlags.None);
                    if (iLen <= 0)
                    {
                        Console.WriteLine("impossiable");
                    }
                }
                catch (System.Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                m_stream.Reset();
            }
            //发送完了挂起
            Suspend();
        }

        public void SendMessage(ref List<NetMessage> listMsg)
        {
            if (listMsg.Count == 0)
            {
                return;
            }
            m_Lock.WaitOne();
            foreach(NetMessage msg in listMsg)
            {
                m_listMsg.Add(msg);
            }
            m_Lock.ReleaseMutex();
            if (m_listMsg.Count > 0)
            {
                Resume();
            }
        }

        public int MakeBuffer(ref LusuoStream lf)
        {
            if (m_listMsg.Count > 0)
            {
                m_Lock.WaitOne();
                foreach (NetMessage msg in m_listMsg)
                {
                    m_listDelegates.Add(msg);
                }
                m_listMsg.Clear();
                m_Lock.ReleaseMutex();
            }
            if (m_listDelegates.Count > 0)
            {
                return __MakeBuffer(ref lf);
            }
            return 0;
        }

        private int __MakeBuffer(ref LusuoStream lf)
        {
            int iFreeBuffer = (int)m_uBufferSize;
            int i = 0;
            for (; i < m_listDelegates.Count; i++)
            {
                m_listDelegates[i].MakeMessage();
                //不够了。下帧再发
                if (iFreeBuffer - m_listDelegates[i].m_uMsgLenght <= 0)
                {
                    //TODO:以后扩展为可以支持任意大小的缓冲
                    //Debug.LogWarning("消息缓冲区不够了。消息" + m_listDelegates[i].m_uID.ToString() + "隔帧发送");
                }
                else
                {
                    iFreeBuffer -= m_listDelegates[i].ToByte(ref lf);
                }
            }
            if (i < m_listDelegates.Count)
            {
                m_listDelegates.RemoveRange(0, i);
            }
            else
            {
                m_listDelegates.Clear();
            }
            return i;
        }

        protected LusuoStream m_stream = null;
    }
}

 

原创粉丝点击