Week 08-day02-Unity网络通讯之聊天室

这篇具有很好参考价值的文章主要介绍了Week 08-day02-Unity网络通讯之聊天室。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、搭建Unity聊天室UI界面

简单UI拖拽一下:

Week 08-day02-Unity网络通讯之聊天室

 聊天室实现步骤:
1.向服务器发送消息
2.刷新Content聊天界面
3.清空输入框

将InputField中输入的消息发给服务器

 代码:

chatPanel:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class ChatPanel : MonoBehaviour
{
    StringBuilder stringBuilder=new StringBuilder("");
    TMP_InputField TMP_input;
    Button button;
    InputField inputfield;
    Text content;

    //获取相关的组件
    private void Awake()
    {
        TMP_input = transform.Find("InputField").GetComponent<TMP_InputField>();
        content = GameObject.Find("Content").GetComponent<Text>();
        button = transform.Find("Btn_Send").GetComponent<Button>();
        button.onClick.AddListener(OnSend);
    }

    // Start is called before the first frame update
    void Start()
    {
        
        
    }


    private void OnSend()
    {
        if (string.IsNullOrEmpty(TMP_input.text))
        {
            return;
        }
        Debug.Log(TMP_input.text);
        //将内容发送给服务器
        NetManager.Instance.SendMessageToServer(TMP_input.text);
        //刷新界面
        UpdateContent(TMP_input.text);
        //将输入框清空
        TMP_input.text = "";
    }

    void UpdateContent(string message)
    {
        stringBuilder.AppendLine(message);
        content.text = stringBuilder.ToString();

    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

问题:为什么要使用到StringBuilder,有什么好处?StringBuilder常见的API有哪些?

NetManager:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;

public class NetManager : MonoBehaviour
{
    //单例
    private static NetManager _instance = null;

    public static NetManager Instance
    {
        get
        {
            return _instance;
        }
    }
    // Start is called before the first frame update
    //客户端连接服务器
    //1.连接到服务器
    //2.接受服务器的消息,并处理
    //3.向服务器发送消息
    byte[] msgArr = new byte[1024];
    Socket clientSocket = null;
    
    //消息队列,用于处理消息
    Queue<string> messageQueue = new Queue<string>();

    private void Awake()
    {
        _instance = this; 
    }
    
    void Start()
    {
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(Protocol.ProtocolConfig.ip), Protocol.ProtocolConfig.port));
        Debug.Log("客户端开始连接服务器!");
        try
        {
            clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
            
        }

    }

    //接受服务器的消息
    private void AsyncReceive(IAsyncResult ar)
    {
        Socket clientSocket = ar.AsyncState as Socket;
        if (clientSocket == null)
        {
            return;
        }
        int length = clientSocket.EndReceive(ar);
        string message = Encoding.UTF8.GetString(msgArr, 0, length);//接受的消息,思考为啥不在这个函数里面处理消息
                                                                    //异步的本质是一条多线程,很多Unity的API没有办法在支线程中使用
        messageQueue.Enqueue(message);

        clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);

        
    }

    public void SendMessageToServer(string message)
    {
        clientSocket.Send(Encoding.UTF8.GetBytes(message));
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            SendMessageToServer("helloWorld");
        }

        if (messageQueue.Count>0)
        {
            string message = messageQueue.Dequeue();

            //处理这个消息
            Debug.Log(message);
        }
    }
}

加上服务器运行截图:

Week 08-day02-Unity网络通讯之聊天室

二、消息号改写聊天室

Week 08-day02-Unity网络通讯之聊天室

代码:

服务端:

动态链接库:ProtocolConfig:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Protocol
{
    //class,struct,interface默认的访问权限修饰符为internal 
    public class ProtocolConfig
    {
        public const string ip = "192.168.1.";
        public const int port = 8899;
    }
}

动态链接库:ProtocolEnum:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Protocol
{
    public enum ProtocolEnum
    {
        loginReq=1,
        loginRep,
        registerReq,
        registerRep,
        updateChat,

    }

}

动态链接库:SocketMessage:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Protocol
{
    public class SocketMessage
    {
        public ProtocolEnum messageId;
        public string message;

        public SocketMessage(ProtocolEnum messageId, string message)
        {
            this.messageId = messageId;
            this.message = message;
        }

        public byte[] PackMessage()
        {
            byte[] idArr = BitConverter.GetBytes((int)messageId);
            byte[] msgArr = Encoding.UTF8.GetBytes(message);

            byte[] result = idArr.Concat(msgArr).ToArray();
            return result;
        }

        public static SocketMessage Parse(byte[] msgArr)
        {
            ProtocolEnum _messageId = (ProtocolEnum)BitConverter.ToInt32(msgArr, 0);
            string _message = Encoding.UTF8.GetString(msgArr, 4, msgArr.Length - 4);

            return new SocketMessage(_messageId,_message);
        }

    }
}

Main函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Protocol;

namespace AsyncChatServer
{
    class Program
    {
       
        static void Main(string[] args)
        {
            try
            {
                Socket Serversocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                
                Serversocket.Bind(new IPEndPoint(IPAddress.Parse(ProtocolConfig.ip),ProtocolConfig.port));
                Serversocket.Listen(10);

                Console.WriteLine("服务器启动了");
                
                
                Serversocket.BeginAccept(AsyncAccept, Serversocket);
            }
            catch (Exception e)
            {
                Console.WriteLine("1"+e.Message);
            }

            Console.ReadKey();

        }

        static byte[] msgarr = new byte[1024];

        private static void AsyncAccept(IAsyncResult ar)
        {
            Socket serversocket = ar.AsyncState as Socket;
            if (serversocket == null)
            {
                return;
            }
            Socket clientsocket = serversocket.EndAccept(ar);

            ClientPeer clientPeer = new ClientPeer(clientsocket);
            NetManager.Instance.AddClient(clientPeer);
            Console.WriteLine(NetManager.Instance); 
            Console.WriteLine(clientsocket.RemoteEndPoint.ToString());
            //clientsocket.beginreceive(msgarr, 0, msgarr.length, socketflags.none, asyncreveive, clientsocket);

            serversocket.BeginAccept(AsyncAccept, serversocket);


        }
    }
}

NetManager:

using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace AsyncChatServer
{

    class NetManager
    {
        private static NetManager _instance = null;
        private NetManager()
        {
            //开启一条线程处理消息队列中的消息
            Thread thread = new Thread(DealWithMessage);
            thread.Start();
        }

        public static NetManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new NetManager();
                }
                return _instance;
            }
        }

        //消息的广播:需要使用List容器存储与客户端建立的连接
        private static List<ClientPeer> clientList = new List<ClientPeer>();

        //消息队列
        Queue<ClientMessage> messageQueue = new Queue<ClientMessage>();

        public void AddClient(ClientPeer client)
        {
            clientList.Add(client);
        }

        public void RemoveClient(ClientPeer client)
        {
            clientList.Remove(client);
        }

        //广播消息
        public void BoardCastMessage(ProtocolEnum messageId, string message,ClientPeer client = null)
        {
            for (int i = 0; i < clientList.Count; i++)
            {
                if (client!=null&& clientList[i] == client)
                {
                    continue;
                }
                clientList[i].SendMessage(messageId,message);
            }
        }
        public void BoardCastMessage(byte[] message, ClientPeer client = null)
        {
            for (int i = 0; i < clientList.Count; i++)
            {
                if (client != null && clientList[i] == client)
                {
                    continue;
                }
                clientList[i].SendMessage(message);
            }
        }

        public void SendMessage(byte[] message,ClientPeer client)
        {
            client.SendMessage(message);
        }

        public void SendMessage(ProtocolEnum messageId,string message, ClientPeer client)
        {

            client.SendMessage(messageId,message);
        }

        public void AddMessage(byte[] msgArr,ClientPeer clientPeer)
        {
            SocketMessage socketMessage = SocketMessage.Parse(msgArr);
            messageQueue.Enqueue(new ClientMessage(clientPeer, socketMessage));
        }

        private void DealWithMessage()
        {
            while (true)
            {
                if (messageQueue.Count > 0)
                {
                    ClientMessage clientMessage = messageQueue.Dequeue();
                    switch (clientMessage.message.messageId)
                    {
                        case ProtocolEnum.loginReq:
                            break;
                        case ProtocolEnum.loginRep:
                            break;
                        case ProtocolEnum.registerReq:
                            break;
                        case ProtocolEnum.registerRep:
                            break;
                        case ProtocolEnum.updateChat:
                            BoardCastMessage(ProtocolEnum.updateChat, clientMessage.message.message,clientMessage.client);//不给自己发消息
                            Console.WriteLine(clientMessage.message.message);
                            break;
                        default:
                            break;
                    }
                }
            }

        }

    }
}

ClientPeer类:

using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace AsyncChatServer
{
    class ClientPeer
    {
        Socket clientSocket = null;

        static byte[] msgArr = new byte[1024];

        internal ClientPeer(Socket clientSocket)
        {
            this.clientSocket = clientSocket;

            clientSocket.BeginReceive(msgArr,0,msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
        }

        internal void AsyncReceive(IAsyncResult ar)
        {
            try
            {
                Socket clientSocket = ar.AsyncState as Socket;
                int length = clientSocket.EndReceive(ar);
                if (clientSocket == null)
                {
                    clientSocket.Close();
                    NetManager.Instance.RemoveClient(this);
                    return;
                }


                //string message = Encoding.UTF8.GetString(msgArr,0,length);
                //Console.WriteLine(message);
                //广播
                //NetManager.Instance.BoardCastMessage(message, this);
                byte[] arr = new byte[length];
                Array.Copy(msgArr, 0, arr, 0, length);
                NetManager.Instance.AddMessage(arr,this);

                clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
               
                
            }
            catch (Exception e)
            {
                clientSocket.Close();
                NetManager.Instance.RemoveClient(this);
                Console.WriteLine(e.Message);
                return;
            }
            
        }

        public void SendMessage(byte[] message)
        {
            clientSocket.Send(message);
        }

        public void SendMessage(ProtocolEnum messageId , string message)
        {
            SocketMessage msg = new SocketMessage(messageId, message);
            clientSocket.Send(msg.PackMessage());
        }
    }
}

ClientMessage类:

using Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsyncChatServer
{
    /// <summary>
    /// 
    /// </summary>
    class ClientMessage
    {
        public ClientPeer client;
        public SocketMessage message;

        public ClientMessage(ClientPeer client, SocketMessage socketMessage)
        {
            this.client = client;
            this.message = socketMessage;
        }


    }
}

客户端:

ChatPanel脚本:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class ChatPanel : MonoBehaviour
{
    StringBuilder stringBuilder=new StringBuilder("");
    TMP_InputField TMP_input;
    Button button;
    InputField inputfield;
    Text content;

    //获取相关的组件
    private void Awake()
    {
        TMP_input = transform.Find("InputField").GetComponent<TMP_InputField>();
        content = GameObject.Find("Content").GetComponent<Text>();
        button = transform.Find("Btn_Send").GetComponent<Button>();
        button.onClick.AddListener(OnSend);
        NetManager.Instance.updateChat+= UpdateContent;
        Debug.LogError(NetManager.Instance);
    }

    // Start is called before the first frame update
    void Start()
    {
        
    }


    private void OnSend()
    {
        if (string.IsNullOrEmpty(TMP_input.text))
        {
            return;
        }
        Debug.Log(TMP_input.text);
        //将内容发送给服务器
        NetManager.Instance.SendMessageToServer(Protocol.ProtocolEnum.updateChat,TMP_input.text);

        //刷新界面
        UpdateContent(TMP_input.text);
        //将输入框清空
        TMP_input.text = "";
    }

    public void UpdateContent(string message)
    {
        stringBuilder.AppendLine(message);
        content.text = stringBuilder.ToString();

    }
    // Update is called once per frame
    void Update()
    {
        
    }

    
}

NetManager脚本:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
using Protocol;


public class NetManager : MonoBehaviour
{
    //单例
    private static NetManager _instance = null;

    public static NetManager Instance
    {
        get
        {
            return _instance;
        }
    }
    // Start is called before the first frame update
    //客户端连接服务器
    //1.连接到服务器
    //2.接受服务器的消息,并处理
    //3.向服务器发送消息
    byte[] msgArr = new byte[1024];
    Socket clientSocket = null;

    //消息队列,用于处理消息
    Queue<SocketMessage> messageQueue = new Queue<SocketMessage>();

    //public delegate void updateClientMsgDel(string message);
    //public updateClientMsgDel del;
    public event  Action<string> updateChat;

    private void Awake()
    {
        _instance = this; 
    }
    
    void Start()
    {
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(Protocol.ProtocolConfig.ip), Protocol.ProtocolConfig.port));
        Debug.Log("客户端开始连接服务器!");
        try
        {
            clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);
        }
        catch (System.Exception e)
        {
            Debug.Log(e.Message);
            
        }

    }

    //接受服务器的消息
    private void AsyncReceive(IAsyncResult ar)
    {
        Socket clientSocket = ar.AsyncState as Socket;
        if (clientSocket == null)
        {
            return;
        }
        int length = clientSocket.EndReceive(ar);
        byte[] Arr = new byte[length];
        Array.Copy(msgArr, 0, Arr, 0, length);
        SocketMessage message = SocketMessage.Parse(Arr);
        //string message = Encoding.UTF8.GetString(msgArr, 0, length);//接受的消息,思考为啥不在这个函数里面处理消息
        //异步的本质是一条多线程,很多Unity的API没有办法在支线程中使用
        //updateChat(message.message);
        messageQueue.Enqueue(message);

        clientSocket.BeginReceive(msgArr, 0, msgArr.Length, SocketFlags.None, AsyncReceive, clientSocket);

        
    }

    public void SendMessageToServer(ProtocolEnum messageId, string message)
    {
        SocketMessage msg = new SocketMessage(messageId, message);
        clientSocket.Send(msg.PackMessage());

    }

    // Update is called once per frame
    void Update()
    {

        if (messageQueue.Count>0)
        {
            SocketMessage message = messageQueue.Dequeue();
            switch (message.messageId)
            {            
                case ProtocolEnum.loginRep:
                    break;
                case ProtocolEnum.registerRep:
                    break;
                case ProtocolEnum.updateChat:
                    updateChat(message.message);
                    break;
                default:
                    break;
            }
        }
    }

  
}

最后运行:

网络通讯day02

 完整项目学习视频源文件:

链接:https://张pan.baidu.com/s三/1ql3j4JXNboVKYzGn6_80tA    (把张三去掉)
提取码:wwww 
--来自百度网盘超级会员V6的分享文章来源地址https://www.toymoban.com/news/detail-463224.html

到了这里,关于Week 08-day02-Unity网络通讯之聊天室的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 网络通讯组件性能优化之路

    BIO为同步阻塞IO,blocking queue的简写,也就是说多线程情况下只有一个线程操作内核的queue,当前线程操作完queue后,才能给下一个线程操作; 问题 在BIO下,一个连接就对应一个线程,如果连接特别多的情况下,就会有特别多的线程,很费线程;在早期的时候,世界上的计算机

    2024年02月02日
    浏览(50)
  • C++ 简单实现RPC网络通讯

            RPC是远程调用系统简称,它允许程序调用运行在另一台计算机上的过程,就像调用本地的过程一样。RPC 实现了网络编程的“过程调用”模型,让程序员可以像调用本地函数一样调用远程函数。最近在做的也是远程调用过程,所以通过重新梳理RPC来整理总结一下。  

    2023年04月08日
    浏览(44)
  • 网络通讯录服务器

    简易版本 服务端完整版本 客户端完整版本 Protobuf还常⽤于通讯协议、服务端数据交换场景。那么在这个⽰例中,我们将实现⼀个⽹络版本的 通讯录,模拟实现客⼾端与服务端的交互,通过Protobuf来实现各端之间的协议序列化。 需求如下: 客⼾端可以选择对通讯录进⾏以下操

    2024年02月12日
    浏览(47)
  • http和https的区别?(网络通讯)

    HTTP:               HTTP(超文本传输协议)和HTTPS(安全超文本传输协议)都是用于互联网通信的协议,但HTTPS是一种更加安全的协议。 HTTPS:              HTTP是一种明文传输协议,信息传输的过程中没有加密,容易被黑客窃取信息。而HTTPS则在HTTP的基础上增加

    2024年02月14日
    浏览(40)
  • 关于ROS的网络通讯方式TCP/UDP

    ROS 系列学习教程(总目录) TCP/IP协议族为传输层指明了两个协议:TCP和UDP,它们都是作为应同程序和网络操作的中介物。 TCP(Transmission Control Protocol)协议全称是传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。 TCP是面向连接的、

    2024年02月05日
    浏览(44)
  • 【网络】UDP通讯(服务器/客户端)

    前言:UDP通讯实现比较简单,单某些情况下也会使用,建议先看一下说明,然后运行代码感受一下。         传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议。TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输。但U

    2024年02月12日
    浏览(61)
  • Java与Modbus-TCP/IP网络通讯

    通过Java与Modbus-TCP/IP网络通讯实现举例5中的功能

    2024年02月10日
    浏览(50)
  • 内网安全——代理技术Socks5&网络通讯&控制上线

    目录 (一)前置知识 0x01 单机——防火墙之限制出入站 常见主机配置不出网的方式

    2023年04月23日
    浏览(41)
  • 【Flink网络通讯(一)】Flink RPC框架的整体设计

    我们从整体的角度看一下Flink RPC通信框架的设计与实现,了解其底层Akka通信框架的基础概念及二者之间的关系。   Akka是使用Scala语言编写的库,用于在JVM上简化编写具有可容错、高可伸缩性的Java或Scala的Actor模型。Akka基于Actor模型,提供了一个用于构建可扩展、弹性、快速响

    2024年02月21日
    浏览(41)
  • C#里使用UdpClient和线程来创建UDP网络通讯

    C#里使用UdpClient和线程来创建UDP网络通讯 在开发的过程中,时不时就需要使用到UDP通讯。 比如与仪器进行通讯,获取仪器的数据。 又或者与PLC通讯,而PLC采用UDP的协议,而不是使用TCP协议。 作为一个软件开发人员,所以必须要熟练地使用UDP进行通讯, 才可以随着应用范围的

    2023年04月21日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包