关闭

Unity3d网络游戏Socket通讯

标签: Unity
304人阅读 评论(0) 收藏 举报
分类:

网络游戏是一种人们娱乐休闲互交的应用软件。既然是互交,当然需要彼此间的了解通讯。要通讯那必须需要Socket:我们今天要实现的主角即套接字。Socket的英文原义是“孔”或“插座”,正如其英文原意那样,象一个多孔插座。一台电脑机器犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。下面我们来看看下图,游戏中玩家移动是如何通讯:

 

下面是Unity3d游戏通讯Socket实现: BaseGameSocket.cs
@原创:dongfu.luo
using System;
using System.Collections.Generic;
using System.Net.Sockets;

public abstract class BaseGameSocket
{
    //用来接收服务端发过来的缓冲Buff
    private byte[] _data_buffer;

  //缓冲二进制数组从哪里开始读
    private int _data_offset;

//缓冲二进制数组读多少个byte
    private int _data_size;

//游戏服务器IP地址
    private string _ip;
    private bool _is_read_head;

//游戏服务器端口
    private int _port;

//要服务端发送的数据命令列表
    private List<PacketOut> _send_list = new List<PacketOut>();
    private Socket _sock;
    private const int MAX_SEND_QUEUE = 0x3e8;

//清空数据,一般是在断开重联时候调用 
    private void Clear()
    {
        this._ip = null;
        this._port = 0;
        this._sock = null;
        List<PacketOut> list = this._send_list;
        lock (list)
        {
            this._send_list.Clear();
        }
        this._is_read_head = false;
        this._data_buffer = null;
        this._data_offset = 0;
        this._data_size = 0;
    }

//关闭客户端的Socket 
    public void Close()
    {
 try
        {
            Socket socket = this._sock;
            this.Clear();
            if ((socket != null) && socket.Connected)
            {
                socket.Shutdown(SocketShutdown.Both);
                socket.Close();
            }
        }
        catch (Exception exception)
        {
            UEDebug.LogError("Connect: " + exception.ToString());
            this.Error(Lang.GetString("k3432"));
        }
    }

 //连接游戏服务端
public void Connect(string ip, int port)
    {
        try
        {
            this.Close();
            this._ip = ip;
            this._port = port;
            this._sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this._sock.NoDelay = true;
            this._sock.BeginConnect(this._ip, this._port, new AsyncCallback(this.OnConnect), this._sock);
        }
        catch (Exception exception)
        {
            UEDebug.LogError("Connect: " + exception.ToString());
            this.Error(Lang.GetString("k3432"));
        }
    }

//如果Socket没有关闭继续等服务器信息,如果有信息则开始读 
    private void ContinueRead()
    {
        try
        {
            if (this.IsConnected)
            {
this._sock.BeginReceive(this._data_buffer, this._data_offset, this._data_size - this._data_offset, SocketFlags.None, new AsyncCallback(this.OnRead), null);
            }
        }
        catch (Exception exception)
        {
            UEDebug.LogError(exception.ToString());
            this.Error(Lang.GetString("k3432"));
        }
    }


//从发送队列从不断向游戏服务器发送命令 
    private void ContinueSend()
    {
        PacketOut state = null;
        List<PacketOut> list = this._send_list;
 lock (list)
        {
            if (this._send_list.Count == 0)
            {
                return;
            }
            state = this._send_list[0];
            if (state.start)
            {
                return;
            }
            state.start = true;
        }
        Socket sock = state.sock;
        if (sock.Connected)
        {
            sock.BeginSend(state.buff, 0, state.buff.Length, SocketFlags.None, new AsyncCallback(this.OnSend), state);
        }
    }
//发送失败或错误,则关闭Socket一般是网络断了服务器关闭了 
    protected void Error(string msg)
    {
        this.Close();
        this.OnError(msg);
    }

//程序猿都知道这是析构函数 
    ~PackedSocket()
    {
        this.Close();
    }
    public int GetSendQueueSize()
    {
        List<PacketOut> list = this._send_list;
        lock (list)
        {
            return this._send_list.Count;
        }
    }

//此函数由子类去处理 
    protected abstract void OnConnect();

//如果是第一次连接上了,解析消息头
    private void OnConnect(IAsyncResult ret)
    {
        if (ret.AsyncState == this._sock)
        {
            try
            {
                this._sock.EndConnect(ret);
                this.ReadHead();
                this.OnConnect();
            }
            catch (Exception exception)
            {
                  Debug.log(exception);
             }
        }
    }
    protected abstract void OnError(string msg);
    protected abstract void OnPack(byte[] data);

//有服务端信息来,开始解析,现解析信息头再解析消息体
    private void OnRead(IAsyncResult ar)
    {
        try
        {
            if (this.IsConnected)
            {
                int num = this._sock.EndReceive(ar);
                this._data_offset += num;
                if (num <= 0)
                {
                    
                }
                else if (this._data_offset != this._data_size)
                {
                    this.ContinueRead();
                }
                else if (this._is_read_head)
                {
 int num2 = BitConverter.ToInt32(this._data_buffer, 0);
                    this.ReadData(num2);
                }
                else
                {
                    this.OnPack(this._data_buffer);
                    this.ReadHead();
                }
            }
        }
        catch (Exception exception)
        {
      Debug.log(exception);
       }
    }

//如果命令发送成功,检查发送队列是否还有需要发送的命令。如果有则继续发送 
    private void OnSend(IAsyncResult ar)
    {
        PacketOut asyncState = ar.AsyncState as PacketOut;
        Socket sock = asyncState.sock;
        if (sock.Connected)
        {
            sock.EndSend(ar);
            List<PacketOut> list = this._send_list;
            lock (list)
            {
                if (this._send_list.Contains(asyncState))
                {
                    this._send_list.Remove(asyncState);
                }
            }
            this.ContinueSend();
        }
    }
//读取消息体 
    private void ReadData(int pack_len)
    {
        this._is_read_head = false;
        this._data_size = pack_len;
        this._data_offset = 4;
        this._data_buffer = new byte[this._data_size];
        this.ContinueRead();
    }

//读取消息头 
    private void ReadHead()
    {
        this._is_read_head = true;
        this._data_size = 4;
        this._data_offset = 0;
        this._data_buffer = new byte[this._data_size];
        this.ContinueRead();

    }

//具体的发送信息,先把数据发到发送队列 
    public void Send(byte[] buff)
{
        if (this.IsConnected)
        {
            PacketOut item = new PacketOut {
                start = false,
                buff = buff,
                sock = this._sock
            };
            int count = 0;
            List<PacketOut> list = this._send_list;
            lock (list)
            {
                this._send_list.Add(item);
                count = this._send_list.Count;
            }
            if (count > 0x3e8)
            {
                
            }
 else
            {
                this.ContinueSend();
            }
        }
    }
    public bool IsClosed
    {
        get
        {
            return (this._sock == null);
        }
    }
    public bool IsConnected
    {
        get
        {
            return ((this._sock != null) && this._sock.Connected);
        }
    }
private class PacketOut
    {
        public byte[] buff;
        public Socket sock;
        public bool start;
    }
}
0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

[Unity通信]一个基于socket的3DARPG网络游戏(一):建立连接和事件分发

一.客户端 1.定义一个消息体,服务器和客户端通信的时候,传输的就是这样的信息。 using System.Collections; using System.Text; public cl...
  • lyh916
  • lyh916
  • 2015-11-19 20:08
  • 4319

《Unity 3D游戏客户端基础框架》 protobuf网络框架

前言:         protobuf是google的一个开源项目,主要的用途是: 1.数据存储(序列化和反序列化),例如xml和json等; 2.制作网络通信协议; 一、资源下载: 1.git...
  • linshuhe1
  • linshuhe1
  • 2016-08-25 19:44
  • 8776

游戏服务器端通信框架(C++与Socket)

这是一个小型多个对战的游戏服务器端代码,经过修改。 文件一:stdafx.h //-------------------------------------------------------...
  • my2005lb
  • my2005lb
  • 2013-03-18 22:26
  • 11385

[Unity3D ARPG网络游戏编程实践] 网络连接 :unity NetWork与socket的对比(一)

unity3d ARPG网络游戏编程实践 作者:A神 目录 1 网络连接 (unity NetWork与socket的对比) 2 登录界面 (登录协议与模型定制 及流程开发) 3 角色选择 (...
  • kepoon
  • kepoon
  • 2015-05-08 17:28
  • 5729

unity3d网络游戏服务器源码

  • 2017-12-10 18:53
  • 45B
  • 下载

Unity3D网络游戏实战 第01章

  • 2017-08-02 10:59
  • 2.46MB
  • 下载

Unity3D网络游戏实战

  • 2018-01-04 23:28
  • 30.02MB
  • 下载

Unity3D精简版网络游戏雏形(简单网络通信聊天和角色监视案例)

  • 2013-08-21 21:45
  • 44.57MB
  • 下载

Unity3D网络游戏实战游戏开发与设计技术丛书 2016年底出版的

  • 2017-11-15 23:01
  • 39.74MB
  • 下载

在Unity3D的网络游戏中Json实现资源动态加载

用Unity3D制作基于web的网络游戏,不可避免的会用到一个技术-资源动态加载。比如想加载一个大场景的资源,不应该在游戏的开始让用户长时间等待全部资源的加载完毕。应该优先加载用户附近的场景资源,在游...
  • mysouling
  • mysouling
  • 2016-02-24 10:36
  • 1216
    个人资料
    • 访问:9168次
    • 积分:84
    • 等级:
    • 排名:千里之外
    • 原创:6篇
    • 转载:11篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论