zoukankan      html  css  js  c++  java
  • C#网络编程学习(3)---使用Tcp和Unity创建本地聊天室的小案例

    使用Tcp协议实现最简单的本地局域网聊天

    1、思路

    服务器

    1. 先用C#网络编程学习(1)---Socket之Tcp协议的简单使用中方法写可接收多个客户端的连接代码。
    2. 另外写一个类Client专门处理连接的客户端clientSocket。
    3. 在主类中用List存放所有连接的客户端。。
    4. 在Client中给出接收信息(线程),发送信息,是否处于连接状态方法。
    5. 在主类中写广播方法(向所有客户端发送信息)

    Unity客户端UI

    Unity客户端代码

    1. Unity空物体ChatManager中绑定脚本ChatManager
    2. 游戏开始时连接服务器
    3. 点击按钮事件触发Send()发送数据方法
    4. 接收广播消息的方法(线程).

    2、服务器端

    /// <summary>
    /// 主类中写服务器信息
    /// </summary>
    class Program
    {
        //创建一个集合记录所有连接的客户端,当广播消息时,向连接的全体客户端发送消息
        private static List<Client> clientList = new List<Client>();
    
        static void Main(string[] args)
        {
            Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 7788));
            tcpServer.Listen(100);
            Console.WriteLine("server running");
    
            while (true) //用while接收多个客户端连接
            {
                Socket tcpClient = tcpServer.Accept();
                Console.WriteLine("a client is connected");
    
                //因为不仅需要while接收多个客户端,每个客户端也可以一直发送消息。所以单独写个类来控制客户端比较直观方便。
                Client client = new Client(tcpClient);
                clientList.Add(client);
            }
        }
    
        //广播消息  (就是向所有客户端发送消息)
        public static void BroadcastMessage(string message)
        {
            List<Client> notConnectedList = new List<Client>(); //获得所有断开连接的客户端
            //遍历list集合,向所有客户端发送消息
            foreach (var client in clientList)
            {
                if (client.Connected)
                    client.SendMessage(message);
                else
                {
                    notConnectedList.Add(client);
                }
            }
    
            //把所有断开连接的客户端移除
            foreach (var temp in notConnectedList)
            {
                clientList.Remove(temp);
            }
        }
    
    }
    
    /// <summary>
    /// Client类用来和客户端做通信
    /// </summary>
    class Client
    {
        private Socket clientSocket;
        private Thread t;
        private byte[] data = new byte[1024]; //这个是一个数据容器
    
        public Client(Socket s)
        {
            clientSocket = s;
            //启动一个线程 处理客户端的接收
            t = new Thread(ReceiveMessage);
            t.Start();
        }
    
        //接收客户端的消息
        private void ReceiveMessage()
        {
            //循环一直接收客户端的数据
            while (true)
            {
                //在接收数据之前,判断socket连接是否断开
                if (clientSocket.Poll(10, SelectMode.SelectRead))
                {
                    clientSocket.Close();
                    break; //跳出循环,中止线程的执行
                }
    
                int length = clientSocket.Receive(data);
                string message = Encoding.UTF8.GetString(data, 0, length);
    
                //消息的广播,要放在Main里面写,因为在Main中存着所有连接的客户端
                Program.BroadcastMessage(message);
                Console.WriteLine("收到了消息" + message);
            }
        }
    
        //向所有客户端发送消息
        public void SendMessage(string message)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(data);
        }
    
        //判断客户端服务器是否还连接,不连接将在Main里面删去
        public bool Connected
        {
            get { return clientSocket.Connected; }
        }
    }
    

    3、客户端

    public class ChatManager : MonoBehaviour
    {
        private string ipAddress = "192.168.1.2";
        private int port = 7788;
        private Socket clientSocket;
        public InputField textInput; //用户输入框
        
        //接收服务器数据
        private Thread t;
        private byte[] data = new byte[1024];
        private string receiveMessages = "";
        public Text chatText;  //用户聊天框
    
        private void Start()
        {
            ConnectedToServer();
        }
    
        private void Update()
        {
            //时刻检测当接收到数据时,receiveMessages不为空,数据加入到聊天框当中
            if (receiveMessages != null && receiveMessages != "")
            {
                chatText.text += "
    " + receiveMessages;
                receiveMessages = "";
            }
        }
    
        //程序开始时连接服务器
        private void ConnectedToServer()
        {
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //发起连接
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipAddress), port));
    
            //创建一个新的线程用于接收广播消息,因为消息要一直接收的
            t = new Thread(ReceiveMessage);
            t.Start();
        }
    
        //发送数据
        private void SendMessage(string message)
        {
            byte[] data = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(data);
        }
    
        //点击按钮触发
        public void OnSendButtonClick()
        {
            string value = textInput.text;
            SendMessage(value);
            textInput.text = "";
        }
    
        //这个线程方法用于循环接收广播消息
        private void ReceiveMessage()
        {
            while (true)
            {
                //与服务器断开连接时,取消线程
                if (clientSocket.Connected == false)
                {
                    break;
                }
                int length = clientSocket.Receive(data);
                receiveMessages = Encoding.UTF8.GetString(data, 0, length);
                //因为Unity中线程不允许直接操控UI组件,所以间接改变
            }
        }
    }
    

    4、效果

    先打开VS中服务器
    图1:为客户端连接时,服务器弹出连接信息,服务器可以收到客户端发送的消息


    **图2**:为打开两个客户端时,一方发送消息,另一方就可以收到 ![](https://img2018.cnblogs.com/blog/1355434/201905/1355434-20190508133554525-271203991.gif)

    5、百度云源码链接

    链接:https://pan.baidu.com/s/1dsZNw8UQJ8BjJHejBzaOLg
    提取码:3ufk

  • 相关阅读:
    五一集训——图论
    Luogu P3942 将军令
    8.14 Round 1
    8.10 Round 1
    8.9 Round 1
    8.7 Round 2
    8.7 Round 1
    8.6 Round 1
    8.5 Round 2
    FHQ-Treap
  • 原文地址:https://www.cnblogs.com/Fflyqaq/p/10831266.html
Copyright © 2011-2022 走看看