1. 程式人生 > >Unity伺服器客戶端02---接收多個客戶端和迴圈接收訊息

Unity伺服器客戶端02---接收多個客戶端和迴圈接收訊息

伺服器開啟後肯定是等待多個客戶端連線,這裡使用一個死迴圈讓伺服器一直處於等待別客戶端連線的狀態,然後每連線一個客戶端就開啟一個執行緒接收客戶端發來的訊息然後廣播給每個客戶端。

首先是服務端程式碼:

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

namespace MySever
{
    class ClientSocket
    {
        private Socket m_ClientSocket;//當前連線伺服器的客戶端作用Sockets
        private byte[] _buffer = new byte[1024];//開闢一段快取空間
        public ClientSocket(Socket socket)//建構函式,每次例項化就執行函式裡面的程式碼
        {
            m_ClientSocket = socket;
            Thread t = new Thread(RecieveMessage);//每當連線一個客戶端就開始一個執行緒進行訊息的接收
            t.Start();
        }
        /// <summary>
        /// 接收客戶端訊息
        /// </summary>
        public void RecieveMessage()
        {
            while (true)//使用死迴圈一直接收訊息
            {
                if (m_ClientSocket.Poll(10, SelectMode.SelectRead))//判斷客戶端是否還在連線,True是沒有連線,False表示還在連線
                {
                    m_ClientSocket.Shutdown(SocketShutdown.Receive);
                    m_ClientSocket.Close();
                    break;
                }
                int lenght = m_ClientSocket.Receive(_buffer);
                string message = Encoding.UTF8.GetString(_buffer, 0, lenght);
                Console.WriteLine("接受到訊息: " + message + "---來自:" + m_ClientSocket.LocalEndPoint);

                Program.BroadcastMessage(message);//接收到一個客戶端的訊息後廣播到所有的客戶端
            }

        }
        /// <summary>
        /// 向客戶端傳送訊息
        /// </summary>
        /// <param name="message"></param>
        public void SendMessage(string message)
        {
            m_ClientSocket.Send(Encoding.UTF8.GetBytes(message));
        }
        /// <summary>
        /// 客戶端是否連線
        /// </summary>
        public bool Connected
        {
            get { return m_ClientSocket.Connected; }
        }
    }
}

這裡建立了一個新的類ClientSocket用來管理所有連線的客戶端並進行訊息的傳送和接收,同樣使用死迴圈一直接收訊息

下面是開啟伺服器和廣播訊息的程式碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;//引用名稱空間
using System.Net;
using System.Threading;

namespace MySever
{
    class Program
    {
        public static List<ClientSocket> ClientSocketList = new List<ClientSocket>();

        static void Main(string[] args)
        {
            Socket severSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            severSocket.Bind(new IPEndPoint(IPAddress.Parse("192.168.x.xxx"), 1314));
            severSocket.Listen(100);
            Console.WriteLine("伺服器已經啟動");

            while(true)//表示一直接收客戶端,每接收一個客戶端暫停住等待下一個客戶端連線
            {
                Socket socket = severSocket.Accept();
                Console.WriteLine(socket.LocalEndPoint + " :已經連線");
                ClientSocket clientSocket = new ClientSocket(socket);//例項化一個控制客戶端的ClietSocket,在ClientSocket的建構函式裡面進行資料的控制
                ClientSocketList.Add(clientSocket);//每連線一個客戶端,就加入到集合
            }
        }
        /// <summary>
        /// 訊息的廣播,釋出到每個客戶端
        /// </summary>
        /// <param name="message"></param>
        public static void BroadcastMessage(string message)
        {
            List<ClientSocket> breakConnect = new List<ClientSocket>();//表示斷開連線的客戶端
            foreach (var item in ClientSocketList)//遍歷所有連線了伺服器的客戶端
            {
                if (item.Connected)//如果客戶端還在連線
                {
                    item.SendMessage(message);//就向客戶端傳送訊息
                }
                else
                {
                    breakConnect.Add(item);//否則就加入到斷開連線的集合裡
                }
            }
            foreach (var item in breakConnect)//遍歷斷開連線的客戶端
            {
                ClientSocketList.Remove(item);//從連線的客戶端裡移除斷開連線的客戶端
            }
        }
    }
}

程式碼註釋很清楚,每連線一個客戶端就新增到已經連線的客戶端集合裡面,遍歷所有連線的客戶端分別向每個客戶端傳送訊息,並且判斷客戶端的連線狀態,從集合移除沒有連線的客戶端。到此伺服器搭建已經完成,下面是客戶端

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

namespace Client
{
    class Program
    {
        private static byte[] _buffer = new byte[1024];
        private static Socket socket;
        static void Main(string[] args)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ipAdress = IPAddress.Parse("192.168.x.xxx");//獲取需要連線的伺服器地址(使用本機地址)
            IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 1314);//獲取終結點和伺服器的一致
            socket.Connect(ipEndPoint);//連線伺服器
            Console.WriteLine("連線伺服器成功...");

            Thread t = new Thread(RecieveMessage);//開啟一條執行緒進行來自伺服器訊息的接收
            t.Start();

            while (true)//可以迴圈向伺服器傳送訊息
            {
                string input = Console.ReadLine();
                SendMessage(input);
            }
        }
        /// <summary>
        /// 向伺服器傳送訊息
        /// </summary>
        /// <param name="message"></param>
        public static void SendMessage(string message)
        {
            socket.Send(Encoding.UTF8.GetBytes(message));
        }
        /// <summary>
        /// 接收來自伺服器的訊息
        /// </summary>
        public static void RecieveMessage()
        {
            while (true)
            {
                int length = socket.Receive(_buffer);
                string message = Encoding.UTF8.GetString(_buffer, 0, length);
                Console.WriteLine("來自伺服器的廣播訊息: " + message + "---" + socket.LocalEndPoint + "傳送");
            }
        }
    }
}

這裡使用死迴圈可以重複傳送訊息和接收訊息,連線伺服器同樣開啟一個執行緒進行訊息的接收,我們來看看效果。

首先開啟伺服器等待客戶端連線:

開啟第一個客戶端:

開啟第二個客戶端:

由於我這個是同一臺電腦進行的操作,所以客戶端地址是一樣的。

下面從一個客戶端傳送一條訊息:

從第二個客戶端傳送訊息:

到此一個最簡單基礎的多人連線的功能就已經完成了,後面將在Unity使用這個結構製作一個簡易的多人聊天室。