unity 遇见websocket

如题,项目背景:手机端H5需要实时控制PC端参与游戏互动。

服务端用java语言编写,为手机端和PC端消息通信做中间媒介,实时和两端保持长连接通信。通信消息用google开发的protobuf对数据结构进行序列化和反序列化。

手机端H5:

1、js引入第三方protobuf第三方js库,<script type="text/javascript" src="js/protobuf.js"></script>。

2、制定通信协议和字段类型,字段名。把它放入一个消息文件中,便于protobuf解析:部分代码如下:

package message;

syntax = "proto3";
message send{
    int32 pid = 1;
    bytes data = 2;
}
message receive{
    int32 pid=1;
    int64 time=2;
    bytes data=3;
}

3、自行封装消息解析和发送。消息发送: var message = resolver.create(data);
        var databuff = resolver.encode(message).finish();
        var msg = {
            pid: Number(pid),
            data: databuff
        }
        var msg = webSocketProtobuf.send.create(msg);
        var buff = webSocketProtobuf.send.encode(msg).finish();        
        if (webSocketProtobuf.socket.readyState === 1) {
            webSocketProtobuf.socket.send(buff);
        } else {
            if (errorCB)
                errorCB();
        }

消息解析:socket.onmessage = function (evt) {            
            if (typeof (evt.data) == "string") {
                console.log(evt.data);
            } else {
                var reader = new FileReader();
                reader.readAsArrayBuffer(evt.data);
                reader.onload = function (e) {
                    var buf = new Uint8Array(reader.result);
                    var de = webSocketProtobuf.receive.decode(buf);                
                    if (onMessage) {
                        onMessage(de);
                    }
                    reader.onload = null;
                }
            }
        }

4、H5主要调用代码如下:初始化通信: webSocketProtobuf.setWebSocket(wsUrl,OnError,OnOpen,OnMessage);

消息接收根据事先定义好的协议号进行区分以及后续的逻辑处理:

function OnMessage(msg) {
    switch(msg.pid){
        case 3:
            //倒计时等待
            if(loadProgress!=100 && !unfinish){
                InitData();
            }
            let serverTime = webSocketProtobuf.receivetime.decode(msg.data);
            ShowCountTime(serverTime.time);            
        break;

}

}

消息发送接口:

function SendMessage(pid,data) {
    if(webSocketProtobuf.socket == null && !isOver){
        if (null != wsUrl) {
            webSocketProtobuf.setWebSocket(wsUrl,OnError,OnOpen,OnMessage);
        }
        return;
    }
    if(data.length != 0){
        webSocketProtobuf.sendData(pid,data,null);
    }
}

5、加一个守护线程定时发送心跳协议,维护长连接。

至此移动端暂告一段落。

PC端:

unity websocket这边我用的BestHttp插件。

1、导入BestHttp插件,用于websocket通信。

2、导入protobuf的dll动态库, 用于后续的消息解析和序列化。官网下载的时候会有一个C#的消息生成bat文件,首先创建一个文件,文件内容包括和服务器通信的消息协议,内容如下:

message basemessage{
    required int32 pid=1;
    required bytes data=2;
}
message receivemessage{
    required int32 pid=1;
    required int64 time=2;
    required bytes data=3;
}

点击生成对应的c#脚本,注意文件的路径点击生成dll直接导入直接代替刚才生成的.cs文件,还是很方便的。

3、接下来就是unity接收消息和发送消息:

 //连接服务器
    public void ConnectWebSocket( string webUrl, string screenId, System.Action<int, ProtoBuf.IExtensible> receiveCallBack )
    {
        if( null != webSocket )
        {
            CloseWebsocket();
        }

        if( null != receiveCallBack )
        {
            callBack = receiveCallBack;
        }

        webAddress = string.Format( webAddress, webUrl, screenId );

        webSocket = new WebSocket( new System.Uri( webAddress ) );

        webSocket.StartPingThread = true;

        if( HTTPManager.Proxy != null )
        {
            webSocket.InternalRequest.Proxy = new HTTPProxy( HTTPManager.Proxy.Address, HTTPManager.Proxy.Credentials, false );
        }

        webSocket.OnOpen += OnOpen;

        webSocket.OnBinary += OnBinaryReceived;

        webSocket.OnClosed += OnClosed;

        webSocket.OnError += OnError;

        webSocket.Open();
    }

消息接收解析:

 void OnBinaryReceived( WebSocket ws, byte[] byteArr )
    {
        ProtoMessage.receivemessage receivemessage = DeserializeProto( byteArr, typeof( ProtoMessage.receivemessage ) ) as ProtoMessage.receivemessage;

        ProtoBuf.IExtensible extensible = null;

        Debug.LogError( receivemessage.pid );

        switch( receivemessage.pid )
        {
            case 2:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receiveuserinfo ) ) as ProtoMessage.receiveuserinfo;                
                break;
            case 4:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receiveplayer ) ) as ProtoMessage.receiveplayer;
                break;
            case 11:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receivequit ) ) as ProtoMessage.receivequit;
                break;
            case 5:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receiverole ) ) as ProtoMessage.receiverole;
                break;
            case 12:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receiveitem ) ) as ProtoMessage.receiveitem;
                break;
            case 10:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receivespeed ) ) as ProtoMessage.receivespeed;
                break;
            case 8:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.reveivegameover ) ) as ProtoMessage.reveivegameover;
                break;
            case 7:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.receivegetitem ) ) as ProtoMessage.receivegetitem;
                break;
            case 9:
                extensible = DeserializeProto( receivemessage.data, typeof( ProtoMessage.heart ) ) as ProtoMessage.heart;

                OnHandleHeart( extensible );
                return;
        }

        if( null != callBack )
        {
            callBack( receivemessage.pid, extensible );
        }
    }

反序列化消息内容:

 //DeserializeProto
    private ProtoBuf.IExtensible DeserializeProto( byte[] buffer, Type type )
    {
        ProtoBuf.IExtensible proto = null;

        using( System.IO.MemoryStream ms = new System.IO.MemoryStream() )
        {
            ms.Write( buffer, 0, buffer.Length );

            ms.Seek( 0, System.IO.SeekOrigin.Begin );

            proto = serializer.Deserialize( ms, null, type ) as ProtoBuf.IExtensible;

            ms.Close();                    
        }

        return proto;
    }

 

向服务端发送消息:

 //send bytearr message
    public void SendMessage( int pid, ProtoBuf.IExtensible proto )
    {
        byte[] buffer = SerializeProto( proto );

        ProtoMessage.basemessage basemessage = new ProtoMessage.basemessage();

        basemessage.pid = pid;

        basemessage.data = buffer;

        byte[] sendBuff = SerializeProto( basemessage );

        if( null != webSocket )
        {
            webSocket.Send( sendBuff );
        }
    }

序列化消息:

 //serialze the protot
    byte[] SerializeProto( ProtoBuf.IExtensible proto )
    {
        byte[] protoBuff = null;

        using( System.IO.MemoryStream ms = new System.IO.MemoryStream() )
        {
            serializer.Serialize( ms, proto );

            if( ms.Length > 0 )
            {
                protoBuff = new byte[(int)ms.Length];

                ms.Seek( 0, System.IO.SeekOrigin.Begin );

                ms.Read( protoBuff, 0, protoBuff.Length );
            }

            ms.Close();
        }        

        return protoBuff;
    }

4、和移动端一样创建一个守护线程,发送心跳协议:

 //守护线程
    private void HeartThread()
    {
        while( true )
        {
            long curTime = Global.GetTimeStamps();

            if( curTime - lastTime >= 5000 )
            {
                lock( connectObj )
                {
                    SendHeartMessage();
                }
            }

            if( !IsConnecting )
            {
                break;
            }
                                    
            Thread.Sleep( 1000 );
        }
    }

以上是用到的主要的代码,并不是全部代码,如需请留言探讨。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Unity UnityWebSocket插件是一款用于在Unity项目中实现WebSocket通信的插件。WebSocket是一种新的网络通信协议,它建立在HTTP协议之上,可以提供全双工通信,使得客户端和服务器可以通过一次HTTP握手建立持久的连接,实现实时的双向通信。 Unity UnityWebSocket插件可以方便地在Unity中使用WebSocket协议进行网络通信。它提供了简洁易用的API接口,开发者可以轻松地实现连接、发送和接收消息等操作。通过该插件,我们可以构建实时的游戏功能,例如聊天系统、多人游戏和实时更新等。 使用Unity UnityWebSocket插件,开发者可以通过几行代码实现WebSocket的连接和消息处理。首先需要创建WebSocket连接,通过指定服务器地址和端口号等参数进行连接。连接建立后,可以通过发送消息来与服务器进行通信,并通过接收消息事件来处理服务器返回的数据。 Unity UnityWebSocket插件还提供了一些高级功能,例如心跳机制和断线重连。心跳机制可以保持连接的稳定性,防止连接断开。断线重连功能可以在网络连接断开后自动重新连接服务器,确保通信的连续性。 总之,Unity UnityWebSocket插件是一款强大的工具,可以帮助开发者在Unity中实现WebSocket通信。它提供了简单易用的接口,并支持一些高级功能,使得开发者可以轻松地构建实时的游戏功能。该插件的使用可以提高开发效率,为游戏开发带来更多可能性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑夜里的四叶草

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值