socket.IO通信

using BestHTTP.ServerSentEvents;
using BestHTTP.SignalR;
using BestHTTP.SignalR.Hubs;
using BestHTTP.SignalR.Messages;
using BestHTTP.SocketIO;
using LitJson;
using System;
using System.Collections.Generic;
using UnityEngine;

public class MySocketIO : MonoBehaviour
{

    void Start()
    {

    }
    void ConnectingToNamespaces()
    {
        SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
        //默认情况下,SocketManager将在连接到服务器时连接到根(“/”)名称空间。 你可以通过SocketManager的Socket属性来访问它:
        Socket root = manager.Socket;
        //可以通过GetSocket(“/ nspName”)函数或通过管理器的索引器属性访问非默认名称空间:
        Socket nsp1 = manager["/customNamespace"];
        Socket nsp2 = manager.GetSocket("/customNamespace");
        //首次访问命名空间将会启动内部连接程序
    }
    //您可以订阅预定义和自定义事件
    void SubscribingAndReceivingEvents()
    {
        SocketManager manager = new SocketManager(new Uri("http://chat.socket.io/socket.io/"));
        //预定义事件
        //connect:当命名空间打开时发送
        //connecting:当SocketManager开始连接到socket.io服务器时发送
        //event:根据自定义(程序员定义的)事件发送
        //disconnect:在传输断开时,SocketManager关闭,Socket关闭或在握手数据中指定的给定时间内未收到服务器的Pong消息时发送
        //reconnect:插件成功重新连接到socket.io服务器时发送
        //reconnecting:当插件尝试重新连接到socket.io服务器时发送
        //reconnect_attempt:当插件尝试重新连接到socket.io服务器时发送
        //reconnect_failed:当重新连接尝试无法连接到服务器并且ReconnectAttempt达到选项'ReconnectionAttempts'值时发送
        //error:发送到服务器或内部插件错误。 该事件的唯一参数将是一个BestHTTP.SocketIO.Error对象

        //自定义事件
        //自定义事件是程序员定义的事件,您的服务器将发送给您的客户端。 您可以通过调用套接字的On函数来订阅事件
        manager.Socket.On("login", (socket, packet, args) => { });
        //socket参数将是服务器发送此事件的名称空间套接字对象。 
        //packet参数包含事件的内部数据包数据。 该数据包可用于访问服务器发送的二进制数据,或使用定制的Json解析器库来解码有效载荷数据
        //args参数是一个可变长度数组,它包含来自数据包有效负载数据的已解码对象。
        //使用默认的Json编码器,这些参数可以是对象的“原始”类型(int,double,string)或对象列表(List <object>)或Dictionary <string,object>

        //服务器上发出的消息
        //socket.emit('message', ‘MyNick’, ‘Msg to the client’); 
        //客户端捕获的消息
        //订阅message事件
        manager.Socket.On("message", (socket, packet, args) =>
        {
            Debug.Log(string.Format("Message from {0}: {1}", args[0], args[1]));
        });


        //其它与事件相关的功能
        //Once:你可以订阅一个仅调用一次的事件
        manager.Socket.Once("connect", (socket, packet, args) => { });
        //off:取消订阅
        manager.Socket.Off();//取消所有订阅的事件
        manager.Socket.Off("connect");//对事件"connect"取消订阅
                                      //manager.Socket.Off("connect", OnConnected); //从事件"connect"中移除OnConnected方法
    }
    //向服务器发送确认 
    void SendingAcknowledgement()
    {
        SocketManager manager = new SocketManager(new Uri(""));
        //可以通过调用套接字的EmitAck函数向服务器发回确认
        //必须传递原始数据包和可选数据:
        manager["/customNamespace"].On("customEvent", (socket, packet, args) =>
        {
            socket.EmitAck(packet, "Event", "Received", "Successfully");
        });
    }
    void SendingBinaryData()
    {
        SocketManager manager = new SocketManager(new Uri(""));
        //有两种方式发送二进制数据
        //一.
        //通过Emit函数传递,插件将扫描参数,如果它找到一个参数,它会将其转换为二进制附件(如在Socket.IO 1.0中介绍的)。
        //这是最有效的方法,因为它不会将字节数组转换为客户端上的Base64编码字符串,并且在服务器端将其转换为二进制。
        byte[] data = new byte[10];
        manager.Socket.Emit("eventWithBinary", "textual param", data);
        //二.
        //如果二进制数据作为字段或属性嵌入对象中,则Json编码器必须支持该转换。 
        //默认的Json编码器不能将嵌入的二进制数据转换为Json,你必须使用更高级的Json解析器库(比如“JSON .NET for Unity” - http://u3d.as/5q2)
    }
    void ReceivingBinaryData()
    {
        SocketManager manager = new SocketManager(new Uri(""));
        //在Socket.IO服务器中,当二进制数据发送到客户端时,它将用Json对象({'_ placeholder':true,'num':xyz})替换数据,并将二进制数据发送到另一个数据包中
        //在客户端,这些数据包将被收集并合并为一个数据包
        //二进制数据将位于数据包的Attachments属性中
        //在这里你将有一些使用这个数据包的选择:
        //一、
        //在事件处理函数中,您可以通过数据包的Attachments属性访问所有二进制数据
        manager.Socket.On("frame", (socket, packet, args) =>
        {
            Texture2D texture2D = new Texture2D(0, 0);
            texture2D.LoadImage(packet.Attachments[0]);
        });
        //二、
        //第二个选项与前一个选项几乎相同,但有一点改进:我们不会将发送的Json字符串解码为c#对象
        //我们可以这样做,因为我们知道服务器只发送二进制数据,这个事件没有其他信息。 所以我们会让插件知道不要解码有效载荷:
        manager.Socket.On("frame", (socket, packet, args) =>
        {
            Texture2D texture2D = new Texture2D(0, 0);
            texture2D.LoadImage(packet.Attachments[0]);
        }, false);
        //三、
        //我们可以将“{'_placeholder':true,'num':xyz}”字符串替换为Attachments列表中Attachment的索引
        manager.Socket.On("frame", (socket, packet, args) =>
        {
            //用索引替换Json对象
            packet.ReconstructAttachmentAsIndex();
            //解码有效载荷到object[]
            args = packet.Decode(socket.Manager.Encoder);
            //现在args只包含一个索引号(可能是0)
            byte[] data = packet.Attachments[Convert.ToInt32(args[0])];

            Texture2D texture2D = new Texture2D(0, 0);
            texture2D.LoadImage(data);
        }, false);
    }
    //设置默认的Json编码器
    //如果由于各种原因想要更改默认的Json编码器,首先必须编写一个新的Json编码器
    //为此,必须编写一个新的类,该类可以从BestHTTP.SocketIO.JsonEncoders命名空间实现IJsonEncoder
    //剥离的IJsonEncoder非常小,你只需要实现两个功能:
    public interface IJsonEncoder
    {
        List<object> Decode(string json);
        string Encode(List<object> obj);
    }
    //Decode函数必须将给定的json字符串解码为对象列表。 由于Socket.IO协议的性质,发送的json是一个数组,第一个元素是事件的名称。

    //编码功能用于对客户想要发送到服务器的数据进行编码
    //该列表的结构与Decode相同:列表的第一个元素是事件的名称,其他任何元素都是用户发送的参数。

    //下面是使用示例文件夹中的LitJson库的完整示例:
    public sealed class LitJsonEncoder : IJsonEncoder
    {
        public List<object> Decode(string json)
        {
            JsonReader reader = new JsonReader(json);
            return JsonMapper.ToObject<List<object>>(reader);
        }

        public string Encode(List<object> obj)
        {
            JsonWriter writer = new JsonWriter();
            JsonMapper.ToJson(obj, writer); return writer.ToString();
        }
    }
    //发生服务器端或客户端错误时发生的“error”事件
    //事件的第一个参数将是一个Error对象。 这将包含Code属性中的错误代码和Message属性中的字符串消息
    //ToString()函数在这个类中被覆盖,你可以使用这个函数写出它的内容。
    void ErrorHandling()
    {
        SocketManager manager = new SocketManager(new Uri(""));
        manager.Socket.On(SocketIOEventTypes.Error, (socket, packet, args) =>
        {
            Error error = args[0] as Error;

            switch (error.Code)
            {
                case SocketIOErrors.User:
                    Debug.Log("Exception in an event handler!");
                    break;
                case SocketIOErrors.Internal:
                    Debug.Log("Internal error!");
                    break;
                default:
                    Debug.Log("Server error!");
                    break;
            }

            Debug.Log(error.ToString());
        });
    }
    //可以将SocketOptions实例传递给SocketManager的构造函数
    //可以更改以下选项: 
    //Reconnection:断开连接后是否自动重新连接。它的默认值是true。 
    //ReconnectionAttempts:放弃之前的尝试次数。它的默认值是Int.MaxValue
    //ReconnectionDelay:尝试重新连接之前最初等待多久。受+/- RandomizationFactor影响。例如,默认的初始延迟将在500毫秒到1500毫秒之间。其默认值是10000ms
    //ReconnectionDelayMax:重新连接之间等待的最长时间。如上所述,每次尝试都会增加重新连接延迟以及随机化。其默认值是5000ms
    //RandomizationFactor:它可以用来控制ReconnectionDelay范围。它的默认值是0.5,可以在0..1的值之间进行设置。 
    //Timeout:发出“connect_error”和“connect_timeout”事件之前的连接超时。它不是底层的tcp套接字的连接超时,而是socket.io协议。它的默认值是20000ms
    //AutoConnect:通过将此设置为false,只要您决定适当,就必须调用SocketManager的Open()。 
    //当你创建一个新的SocketOptions对象时,它的属性被设置为它们的默认值。
    //BestHTTP.SignalR命名空间中的Connection类管理到SignalR服务器的抽象连接
    //连接到SignalR服务器从创建Connection对象开始
    //该类将跟踪协议的当前状态并将触发事件
    void TheConnectionClass()
    {
        //你有多个途径创建一个连接对象
        Uri uri = new Uri("");
        //通过仅将服务器的URI传递给构造函数来创建连接,而不使用集线器
        Connection signlRConnection1 = new Connection(uri);
        //通过将集线器名称也传递给构造函数来创建连接,并使用集线器
        Connection signlRConnection2 = new Connection(uri, "hub1", "hub2", "hubN");
        //通过将Hub对象传递给构造函数来创建连接,并使用Hub
        //using BestHTTP.SignalR.Hubs;
        Hub hub1 = new Hub("hub1");
        Hub hub2 = new Hub("hub2");
        Hub hubN = new Hub("hubN");
        Connection signlRConnection3 = new Connection(uri, hub1, hub2, hubN);
        //在创建Connection之后,我们可以通过调用Open()函数来开始连接到服务器
        signlRConnection1.Open();
    }
    void HandlingGeneralEvents()
    {
        Uri uri = new Uri("");
        Connection signlRConnection = new Connection(uri);
        //Connection类将允许您订阅多个事件,这些事件如下:
        //OnConnected:当connection类成功连接并且SignalR协议用于通信时,会触发此事件
        signlRConnection.OnConnected += (con) => Debug.Log("Connected to the SignalR server!");
        //OnClosed:当SignalR协议关闭时会触发此事件,并且不再发送或接收更多消息
        signlRConnection.OnClosed += (con) => Debug.Log("Connection Closed");
        //OnError:发生错误时调用。 如果连接已经打开,插件将尝试重新连接,否则连接将被关闭
        signlRConnection.OnError += (con, err) => Debug.Log("Error: " + err);
        //OnReconnecting:当重新连接尝试开始时,将触发此事件
        //在此事件之后,将调用OnError或OnReconnected事件
        //在OnReconnected / OnClosed事件之前可以触发多个OnReconnecting-OnError事件对,因为插件会在给定的时间内尝试重新连接多次。
        signlRConnection.OnReconnecting += (con) => Debug.Log("Reconnecting");
        //OnReconnected:重新连接尝试成功时触发
        signlRConnection.OnReconnecting += (con) => Debug.Log("Reconnected");
        //OnStateChnaged:连接状态改变时触发,事件处理程序将收到旧状态和新状态
        signlRConnection.OnStateChanged += (conn, oldState, newState) => Debug.Log(string.Format("State Changed {0} -> {1}", oldState, newState));
        //OnNonHubMessage:服务器向客户端发送非集线器消息时触发
        //客户端应该知道服务器期望的消息类型,并且应该相应地转换接收到的对象
        signlRConnection.OnNonHubMessage += (con, data) => Debug.Log("Message from server: " + data.ToString());
        //RequestPreparator:每个HTTPRequest都会调用这个委托并将发送到服务器, 它可以用来进一步自定义请求
        signlRConnection.RequestPreparator = (con, req, type) => req.Timeout = TimeSpan.FromSeconds(30);
    }
    void SendingNonHubMessages()
    {
        Uri uri = new Uri("");
        Connection signlRConnection = new Connection(uri);
        //发送非集线器消息到服务器像在connection对象上调用一个函数一样容易:
        signlRConnection.Send(new { Type = "Broadcast", Value = "Hello SignalR World!" });
        //此函数将使用Connection的JsonEncoder将给定对象编码为Json字符串,并将其发送到服务器
        //已编码的Json字符串可以使用SendJson函数发送:
        signlRConnection.SendJson("{ Type: ‘Broadcast’, Value: ‘Hello SignalR World!’ }");
    }
    //为了定义客户端上Hub可以从服务器调用的方法,并在服务器上调用Hub上的方法,必须将Hubs添加到Connection对象中
    //这可以通过将集线器名称或集线器实例添加到Connection构造函数中完成,在Connection Class部分中已进行演示
    //using BestHTTP.SignalR.Messages;
    void Hubs()
    {
        Uri uri = new Uri("");
        Connection signalRConnection = new Connection(uri);
        //Accessing hubs (访问集线器)
        Hub hub1 = signalRConnection[0];
        Hub hub2 = signalRConnection["hubName"];
        //Register server callable methods(注册服务器可调用方法)
        //要处理服务器可调用方法的调用,我们必须调用集线器的On函数:
        signalRConnection["hubName"].On("joined", (hub, msg) =>
        {
            Debug.Log(string.Format("{0} joined at {1}", msg.Arguments[0], msg.Arguments[1]));
        });

        //On的第二个参数类型是MethodCallMessage
        //MethodCallMessage是一个服务器发送的对象,它包含以下属性:
        //Hub:包含该方法必须调用的集线器名称的字符串
        //Method:包含方法名称的字符串
        //Arguments:包含方法调用参数的对象数组。 它可以是一个空数组
        //State:包含其他自定义数据的字典。

        //该插件将使用Hub和Method属性将消息发送到正确的集线器和事件处理程序。 处理方法调用的函数只能使用参数和状态属性

        //Call server-side methods (调用服务端方法)
        //调用服务器端方法可以通过调用Hub的Call函数来完成
        //重载的调用函数能够满足每个需求
        //Call函数是非阻塞函数,它们不会阻塞,直到服务器发送有关该呼叫的任何消息
        //重载如下:
        //Call(string method, params object[] args): 
        //这可用于以fireand -forget样式调用服务器端函数
        //我们不会收到有关方法调用成功或失败的消息。 这个函数可以在没有任何'args'参数的情况下调用,以调用无参数方法
        signalRConnection["hubName"].Call("Ping");
        signalRConnection["hubName"].Call("Message", "param1", "param2");
        //Call(string method, OnMethodResultDelegate onResult, params object[] args): 
        //该函数可以作为前一个函数使用,但函数可以传递第二个参数,该函数将在服务器端函数成功调用时调用。
        signalRConnection["hubName"].Call("GetValue", OnGetValueDone);
        //此回调函数接收调用此函数的Hub,发送给服务器的原始ClientMessage消息以及由服务器作为该方法调用结果发送的ResultMessage实例
        //ResultMessage对象包含一个ReturnValue和一个State属性。

        //如果方法的返回类型为void,则ReturnValue为null
        //Call(string method, OnMethodResultDelegate onResult, OnMethodFailedDelegate onError, params object[] args):
        //此函数可指定当方法在服务器上运行失败时调用的回调。 没有找到方法,参数错误或未处理的异常,在方法调用时都可能会引发故障
        signalRConnection["hubName"].Call("GetValue",
        OnGetValueDone,
        OnGetValueFailed);
        //FailureMessage包含以下属性:
        //IsHubError:如果是Hub错误,则为True
        //ErrorMessage:关于错误本身的简短消息
        //StackTrace:如果服务器上打开了详细的错误报告,那么它将包含错误的堆栈跟踪
        //AdditionalData:如果不为空,则它包含有关错误的其他信息


        // Call(string method, OnMethodResultDelegate onResult, OnMethodFailedDelegate onError, OnMethodProgressDelegate onProgress, params object[] args): 
        //该函数可用于向服务器端方法调用添加额外的进度消息处理程序。 对于长时间运行的作业,服务器可以向客户端发送进度消息
        signalRConnection["hubName"].Call("GetValue", OnGetValueDone, OnGetValueFailed, OnGetValueProgress);
    }
    void OnGetValueDone(Hub hub, ClientMessage originalMessage, ResultMessage result)
    {
        Debug.Log("GetValue executed on the server. Return value of the function:" + result.ReturnValue.ToString());
    }
    void OnGetValueFailed(Hub hub, ClientMessage originalMessage, FailureMessage error)
    {
        Debug.Log("GetValue failed. Error message from the server: " + error.ErrorMessage);
    }
    void OnGetValueProgress(Hub hub, ClientMessage originalMessage, ProgressMessage progress)
    {
        Debug.Log(string.Format("GetValue progressed: {0}%", progress.Progress));
    }
    void EventSourceClass()
    {
        EventSource eventSource = new EventSource(new Uri("http://server.com"));

        //Properties 
        //这些是EventSource类公开公开的属性:
        //Uri:这是协议尝试连接的端点。 它通过构造函数设置。 
        //State:EventSource对象的当前状态。 
        //ReconnectionTime:尝试执行重新连接尝试需要等待多少时间。 它的默认值是2秒。
        //LastEventId:最近收到的事件的ID。 如果没有接收到事件ID,它将为空。
        //InternalRequest:将在Open函数中发出的内部HTTPRequest对象。

        //Events 
        //OnOpen:它在协议成功升级时调用
        eventSource.OnOpen += (source) => Debug.Log("EventSource Opened!");
        //OnMessage:它在客户端收到来自服务器的新消息时调用
        //该函数将接收一个Message对象,该对象包含Data属性中消息的有效内容
        //每次客户端收到消息时都会调用此事件,即使消息具有有效的事件名称,并且我们为此事件分配了事件处理程序!
        eventSource.OnError += (source, error) => Debug.Log("Error: " + error);
        //OnRetry:在插件尝试重新连接到服务器之前调用此函数。 如果函数返回false,则不会进行尝试,并关闭EventSource。
        eventSource.OnRetry += (source) => false;
        //OnClosed:EventSource关闭时会调用此事件
        eventSource.OnClosed += (source) => Debug.Log("EventSource Closed!");
        //OnStateChanged:当State属性变化时调用
        eventSource.OnStateChanged += (source, oldState, newState) => Debug.Log(string.Format("State Changed {0} => {1}", oldState, newState));

        //Functions 
        //这些是EventSource对象的公有方法
        // Open: 调用此函数后,插件将开始连接到服务器并升级到ServerSent Events协议
        eventSource.Open();
        // On: 使用这个功能,客户端可以订阅事件
        eventSource.On("userLogon", (source, msg) => { Debug.Log(msg.Data); });
        // Off: 它可以用来取消订阅活动
        eventSource.Close();

    }
    //    Message类是一个逻辑单元,它包含服务器可以发送的所有信息。 
    //属性
    //Id:发送事件的ID。 如果没有ID发送,可以为空。 它由插件使用。 
    //Event:事件的名称。 如果没有发送事件名称,则可以为null。 
    //Data:消息的实际有效负载。 
    //Retry:服务器发送插件在尝试重新连接之前等待的时间。 它由插件使用

    void SampleHubImplement()
    {
        Uri uri = new Uri("");
        SampleHub sampleHub = new SampleHub();
        Connection signalRConnection = new Connection(uri, sampleHub);
    }
}

class SampleHub : Hub
{
    // Default constructor. Every hubs have to have a valid name.  
    public SampleHub() : base("SampleHub")
    {
        // 注册一个服务器可调用函数  
        base.On("ClientFunction", ClientFunctionImplementation);
    }

    // 实现服务器可调用函数的私有函数  
    private void ClientFunctionImplementation(Hub hub, MethodCallMessage msg)
    {
        // 待办事项:实现  
    }

    // 包装器函数调用服务器端函数。  
    public void ServerFunction(string argument)
    {
        base.Call("ServerFunction", argument);
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值