Socket实现聊天室——进阶篇

        在掌握了Socket的基本使用之后,我们就可以使用socket实现一些基本的功能,比如游戏中的聊天功能。我们首先要明白聊天功能的实现原理是什么,拿王者荣耀对战中的聊天功能举例,一个队友发送了消息之后,其他队友都能看到他发的消息,这其中的机制就是该队友(一个客户端)发送消息到服务器端,服务器端接收消息并把该消息广播给其他客户端,由于接收消息需要一直执行,是一个死循环,为了保证后面的代码执行不受影响,还需要使用到线程。

        服务器端:

服务器端有两个类,一个用来控制流程(Program),一个是客户端实体类(Client)。

在Program里定义一个Client类型的动态数组,用来保存连接到的客户端。

        static List<Client> clientList = new List<Client>();

在完成服务器端Socket的创建,绑定ip和端口号和开始监听之后,用之前定义好的数组保存连接到的客户端,而且要一直接受连接的客户端,所以我们需要一个死循环。在循环中我们要接受客户端并且在Client类中定义构造方法进行初始化,同时将客户端保存到数组中。

            while (true) {
                Socket clientSocket = tcpServer.Accept();
                Console.WriteLine("客户端正在连接");
                Client client = new Client(clientSocket);
                clientList.Add(client);
            }

然后定义客户端类,属性有Socket,byte,Thread类型的变量,还要定义ReceiveMessage方法,在构造方法里开启线程用来循环接收消息。

        public Client(Socket s)
        {
            clientSocket = s;
            t = new Thread(ReceiveMessage);
            t.Start();
        }

        void ReceiveMessage()
        {
            while (true)
            {
                //接受数据之前判断socket是否断开
                if (clientSocket.Poll(10,SelectMode.SelectRead))
                {
                    //socket如果断开就关闭连接
                    clientSocket.Close();
                    break;
                }
                int length=clientSocket.Receive(data);
                string message = Encoding.UTF8.GetString(data, 0, length);
                //调用广播消息的方法
                Program.BroadCastMessage(message);
                Console.WriteLine("收到了消息:" + message);
            }
        }

在服务器端接收了消息之后就要广播给其他的客户端,在Program中定义BroadCastMessage静态方法,在ReceiveMessage中调用。在该方法中我们需要判断客户端是否断开连接,已经断开连接的客户端不需要将消息广播给该客户端了,所以定义了一个断开连接的客户端数组,最后将客户端数组中断开连接的去掉。

        public static void BroadCastMessage(string message)
        {
            var notConnected = new List<Client>();
            foreach(var client in clientList)
            {
                if (client.Connected)
                {
                    client.SendMessage(message);
                }
                else
                {
                    notConnected.Add(client);
                }
            }
            foreach(var temp in notConnected)
            {
                clientList.Remove(temp);
            }
        }

        客户端:

我们首先做好准备工作,在unity中简单做一个聊天框的场景,主要包括输入框,button和文本框。

再创建一个空物体,用来挂在客户端的脚本(ChatManager),在ChatManager脚本中创建ConnectedToServer方法,该方法中创建Socket并进行连接,同时开启线程用来接受服务器发送的消息。在ReceiveMessage中接收消息并保存到message中。之后将message中的内容添加到文本框中就将内容显示了。SendMessage方法用来发送消息,OnSendButtonClick用来绑定按钮事件,当点击了按钮之后将输入框中的内容传到SendMessage中,然后消息就被发送到服务器端了。

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

public class ChatManager : MonoBehaviour
{
    public string ipadress = "10.135.21.2";
    public int port = 7788;
    private Socket clientSocket;
    Thread t;
    private byte[] data = new byte[1024];
    string message = "";

    public InputField textInput;
    public Text chatText;


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

    // Update is called once per frame
    void Update()
    {
        if (message != null && message != "")
        {
            chatText.text += "\n" + message;
            message = "";
        }
    }

    void ConnectedToServer()
    {
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //进行连接
        Debug.Log("正在尝试连接");
        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipadress), port));
        Debug.Log("已连接");
        //创建一个新的线程,用来接收消息
        t = new Thread(ReceiveMessage);
        t.Start();
    }

    void ReceiveMessage()
    {
        while (true)
        {
            if (clientSocket.Connected == false)
            {
                break;
            }
            int length = clientSocket.Receive(data);
            message = Encoding.UTF8.GetString(data, 0, length);
        }
    }

    void SendMessage(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        clientSocket.Send(data);
    }

    public void OnSendButtonClick()
    {
        Debug.Log("点击了按钮");
        string value = textInput.text;
        SendMessage(value);
        textInput.text = "";

    }
}

 其实主体部分和基础篇的内容差不多,只不过加了一些线程和一些小细节。最后我们使用两个客户端进行测试。首先将服务器端启动,然后打开两个客户端,先在一个客户端输入“你学会socket了吗”,然后打开另一个客户端输入“记得要经常练习”,可以发现第一个客户端也出现了“记得要经常练习”的消息。这就代表我们的socket通信成功完成。

猜你喜欢

转载自blog.csdn.net/qq_52397831/article/details/126781145
今日推荐