Unity web聊天通讯功能开发(1)

4 篇文章 0 订阅

注:发文章我不像某些大咖只发大概思路,每一步我的操作我都会写下来,如果实在看不懂就去下载我的案例哈,本文章只研究下如何互发文字通讯,web端互发图片的等我研究出来再发哈

Unity做聊天室,网上大多数都是通过socket做的,我之前也尝试了一下不难,但是最近的项目都是发布成webgl,我发现一个问题,那就是web端不支持socket,通过查找资料,我找到另一个通讯方式——websocket,先普及型websocket。

WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。

1.原理:

WebSocket同HTTP一样也是应用层的协议,但是它是一种双向通信协议,是建立在TCP之上的。

2.连接过程 —— 握手过程

  • 1. 浏览器、服务器建立TCP连接,三次握手。这是通信的基础,传输控制层,若失败后续都不执行。
  • 2. TCP连接成功后,浏览器通过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)
  • 3. 服务器收到客户端的握手请求后,同样采用HTTP协议回馈数据。
  • 4. 当收到了连接成功的消息后,通过TCP通道进行传输通信。

3.WebSocket与HTTP的关系

相同点

  • 1. 都是一样基于TCP的,都是可靠性传输协议。
  • 2. 都是应用层协议。

不同点

  • 1. WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息。HTTP是单向的。
  • 2. WebSocket是需要握手进行建立连接的。

联系

WebSocket在建立握手时,数据是通过HTTP传输的。但是建立之后,在真正传输时候是不需要HTTP协议的。

4.WebSocket与Socket的关系

Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

当两台主机通信时,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接。TCP连接则更依靠于底层的IP协议,IP协议的连接则依赖于链路层等更低层次。

WebSocket则是一个典型的应用层协议。

区别

Socket是传输控制层协议,WebSocket是应用层协议。

5.在Unity中,WebSocket比Socket更适用各个平台的开发

以下介绍下Unity发布Web,通讯功能如何做,以聊天室为案例

1.导入BestHttp插件

这个插件包含所有即使通讯方式的简单使用,下载地址为BestHttp通讯插件-C#文档类资源-CSDN下载

2.布置UI

这边我只做了两个简易界面,一个是登录界面,一个是聊天窗口界面,功能如图所示

 

 3.构建服务端

使用VS新建项目C#控制台

 

通过包管理器,引用websocket和litjson相关组件

 

 

 

除了控制台自带的类Program,还需新建类MessageData,ClientController,各代码如下:

using SuperSocket.SocketBase;
using SuperWebSocket;
using System;
using System.Collections.Generic;

class Program
{
    public static List<ClientController> clientControllerList = new List<ClientController>();
    static void Main(string[] args)
    {
       // Console.WriteLine("Press any key to start the WebSocketServer!");

        //Console.ReadKey();
       // Console.WriteLine();

        var appServer = new WebSocketServer();
      

        //Setup the appServer
        if (!appServer.Setup(2012)) //Setup with listening port
        {
            Console.WriteLine("Failed to setup!");
            Console.ReadKey();
            return;
        }

        appServer.NewSessionConnected += delegate (WebSocketSession session)
        {
          //  Console.WriteLine("新玩家加入: " + session.SessionID);
          //  session.Send("新玩家加入: " + session.SessionID);
        };

        appServer.SessionClosed += delegate (WebSocketSession session, CloseReason value)
        {
            
            for (int i = 0; i < clientControllerList.Count; i++)
            {
                if (session.SessionID == clientControllerList[i].session.SessionID)
                {
                    ClientController client = clientControllerList[i];
                 client .SendMessageDataToAllClientWithOutSelf(client.nickName + "离开聊天室");
                    Console.WriteLine(client.nickName+ "离开聊天室");
                    clientControllerList.Remove(clientControllerList[i]);
                    return ;
                }
            }
          
       
        };
        appServer.NewMessageReceived += delegate (WebSocketSession session, string value)
        {
             MessageData data = LitJson.JsonMapper.ToObject<MessageData>(value);
            ClientController clientController =GetClient(session);

            string msg = "";
             switch (data.msgType)
             {

                 case MessageType.Login://如果是登陆消息
                    clientController.nickName = data.nickname;
                   
                  //   session.Send("玩家加入: " + data.name);
                     clientControllerList.Add(clientController);
                    msg = clientController.nickName + "加入聊天室";
                     Console.WriteLine(clientController.nickName + "加入聊天室");
                    break;
                 case MessageType.Chat://如果是聊天消息
                     Console.WriteLine(clientController.nickName + "说: " + data.msg);
                    data.nickname = clientController.nickName;
                    msg = LitJson.JsonMapper.ToJson(data);
                    break;
                 case MessageType.LogOut://客户端请求退出

                     Console.WriteLine(clientController.nickName + "离开聊天室");
                    clientControllerList.Remove(clientController);
                    msg = clientController.nickName + "离开聊天室";

                    break;
             }
            clientController.SendMessageDataToAllClientWithOutSelf(msg);

        };
        Console.WriteLine();

        //Try to start the appServer
        if (!appServer.Start())
        {
            Console.WriteLine("Failed to start!");
            Console.ReadKey();
            return;
        }

        Console.WriteLine("The server started successfully, press key 'q' to stop it!");

        while (Console.ReadKey().KeyChar != 'q')
        {
            Console.WriteLine();
            continue;
        }

        //Stop the appServer
        appServer.Stop();

        Console.WriteLine();
        Console.WriteLine("The server was stopped!");
        Console.ReadKey();
    }

    public static ClientController GetClient(WebSocketSession session)
    {
        for (int i = 0; i < clientControllerList.Count; i++)
        {
            if (session.SessionID == clientControllerList[i].session.SessionID)
            {
                return clientControllerList[i];
            }
        }
        return new ClientController(session);
    }
}
using SuperWebSocket;
using System;

class ClientController
{
    /// <summary>
    /// 用户链接的通道
    /// </summary>
    public WebSocketSession session;
    /// <summary>
    /// 昵称
    /// </summary>
    public string nickName;
    //接收的线程

    public ClientController(WebSocketSession  socket)
    {
        session= socket;
       
    }
    

    /// <summary>
    /// 广播消息,排除掉自己
    /// </summary>
    /// <param name="data"></param>
   public  void SendMessageDataToAllClientWithOutSelf(string data)
    {
        //5   i=3
        for (int i = 0; i < Program.clientControllerList.Count; i++)
        {
            if (Program.clientControllerList[i] != this)
            {
                Program.clientControllerList[i].SendToClient(data);
            }
          

        }
    }


    void SendToClient(string data)
    {
        session.Send(data);
    }
 
   
}
/// <summary>
/// 简单的协议类型
/// </summary>
public enum MessageType
{
    Chat = 0,//聊天
    Login = 1,//登陆
    LogOut = 2,//登出
}
/// <summary>
/// 消息体
/// </summary>
public class MessageData
{
    /// <summary>
    /// 消息类型
    /// </summary>
    public MessageType msgType;
    /// <summary>
    /// 消息内容
    /// </summary>
    public string msg;
    public string nickname;
}

此时点击运行,即可运行服务端

 

 4.客户端代码

新建类WebSocketTest,MessageData,ChatItem,代码如下:

using LitJson;
/// <summary>
/// 简单的协议类型
/// </summary>
public enum MessageType
{
    Chat = 0,//聊天
    Login = 1,//登陆
    LogOut = 2,//登出
}
/// <summary>
/// 消息体
/// </summary>
public class MessageData
{
    /// <summary>
    /// 消息类型
    /// </summary>
    public MessageType msgType;
    /// <summary>
    /// 消息内容
    /// </summary>
    public string msg;
    public string nickname;
}
using System;
using UnityEngine;
using BestHTTP;
using BestHTTP.WebSocket;
using UnityEngine.UI;
using BestHTTP.Examples.Helpers;

namespace BestHTTP.Examples.Websockets
{
    public class WebSocketTest : BestHTTP.Examples.Helpers.SampleBase
    {
        // [SerializeField]
        //  [Tooltip("The WebSocket address to connect")]
        private string address = "ws://192.168.2.50:2012";

        [SerializeField]
        private InputField name_input;
        [SerializeField]
        private InputField content_input;

        [SerializeField]
        private ScrollRect _scrollRect;

        [SerializeField]
        private RectTransform _contentRoot;

        [SerializeField]
        private TextListItem _listItemPrefab;

        [SerializeField]
        private int _maxListItemEntries = 100;
       



#pragma warning restore

        /// <summary>
        /// Saved WebSocket instance
        /// </summary>
        WebSocket.WebSocket webSocket;
        public GameObject loginGo;
        public GameObject chatGo;

        protected override void Start()
        {
            base.Start();
        }
        public void LoginIn()
        {
            if (name_input.text == "" || name_input.text == null)
                return;
            // Create the WebSocket instance
            this.webSocket = new WebSocket.WebSocket(new Uri(address));

#if !UNITY_WEBGL
            this.webSocket.StartPingThread = true;

#if !BESTHTTP_DISABLE_PROXY
            if (HTTPManager.Proxy != null)
                this.webSocket.InternalRequest.Proxy = new HTTPProxy(HTTPManager.Proxy.Address, HTTPManager.Proxy.Credentials, false);
#endif
#endif

            // Subscribe to the WS events
            this.webSocket.OnOpen += OnOpen;
            this.webSocket.OnMessage += OnMessageReceived;
            this.webSocket.OnClosed += OnClosed;
            this.webSocket.OnError += OnError;

            // Start connecting to the server
            this.webSocket.Open();
         //   AddText("Connecting...");

        }
        public void Chat()
        {
            if (content_input.text == "" || content_input.text == null)
                return;
            MessageData data = new MessageData();
            data.msgType = MessageType.Chat;
            data.msg = content_input.text;
            string json = JsonUtility.ToJson(data);
            webSocket.Send(json);
          ChatItem chatItem  =  (ChatItem)AddText(string.Format(" <color=yellow>我:</color>\n{0}",data.msg));
               chatItem.AddLeftPadding(20);
              chatItem.SetTextAlignment(TextAnchor.MiddleRight);

        }


        public void LoginOut()
        {
            MessageData data = new MessageData();
            data.msgType = MessageType.LogOut;
            data.msg = "退出";
            string json = JsonUtility.ToJson(data);
            webSocket.Send(json);
            webSocket.Close(1000, "Bye!");

            webSocket.OnOpen -= OnOpen;
            webSocket.OnMessage -= OnMessageReceived;
            webSocket.OnClosed -= OnClosed;
            webSocket = null;
            AddText("Closing!");
            loginGo.SetActive(true);
            chatGo.SetActive(false);

        }


        #region WebSocket Event Handlers

        /// <summary>
        /// Called when the web socket is open, and we are ready to send and receive data
        /// </summary>
        void OnOpen(WebSocket.WebSocket ws)
        {
            AddText("WebSocket Open!");
            MessageData data = new MessageData();
            data.msgType = MessageType.Login;
            data.nickname = name_input.text;
            string json = JsonUtility.ToJson(data);
            webSocket.Send(json);
            loginGo.SetActive(false);
            chatGo.SetActive(true);
        }



        /// <summary>
        /// Called when we received a text message from the server
        /// </summary>
        void OnMessageReceived(WebSocket.WebSocket ws, string message)
        {
            try
            {
                 MessageData data = JsonUtility.FromJson<MessageData>(message);
            AddText(string.Format(" <color=yellow>{0}:</color>\n{1}", data.nickname,data.msg))
                .AddLeftPadding(20);
            }
            catch (System.Exception ex)
            {
                 AddText(string.Format(" <color=yellow>{0}</color>", message))
                .AddLeftPadding(20);
            }
            
        }

        /// <summary>
        /// Called when the web socket closed
        /// </summary>
        void OnClosed(WebSocket.WebSocket ws, UInt16 code, string message)
        {
            AddText(string.Format("WebSocket closed! Code: {0} Message: {1}", code, message));

            webSocket = null;


        }

        /// <summary>
        /// Called when an error occured on client side
        /// </summary>
        void OnError(WebSocket.WebSocket ws, string error)
        {
            AddText(string.Format("An error occured: <color=red>{0}</color>", error));

            webSocket = null;


        }

        #endregion



        private TextListItem AddText(string text)
        {
            return GUIHelper.AddText(this._listItemPrefab, this._contentRoot, text, this._maxListItemEntries, this._scrollRect);
        }

        void OnDestroy()
        {
            if (this.webSocket != null)
            {
                this.webSocket.Close();
                this.webSocket = null;
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace BestHTTP.Examples.Helpers
{
public class ChatItem : TextListItem
{
  
    public void SetTextAlignment(TextAnchor textAnchor){
        _text.alignment=textAnchor;
    }    
}
}

5.UI绑定功能

先复制一个“TextListItem”预制件,插件BestHttp里面有,然后去除它本身的脚本,挂上ChatItem脚本,成为一个新的预制件,供后面使用。

挂载脚本并赋值

 将登陆按钮绑定登陆方法,发送按钮绑定发送方法

 

 最后我们复制两个聊天系统,运行查看结果

 

 打包web同样适用

demo:unitywebsocket聊天室案例-Unity3D文档类资源-CSDN下载

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值