Unity多路複用服務器端(Select)

在網絡遊戲中,多路複用的方式是最常見的服務器端解決方案,程序結構如圖:

 程序代碼:

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

//保存客戶端信息的類
class ClientState
{
    public Socket socket;
    public byte[] readbuff = new byte[1024];
}
class Server
{
    //新建一個字典用於socket和狀態查詢
    static Dictionary<Socket,ClientState> clients=new Dictionary<Socket,ClientState>();
    static void Main(string[] args)
    {
        //建立Socket並綁定
        Socket listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
        IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);
        listenfd.Bind(ipEp);

        //啓動服務器監聽
        listenfd.Listen(0);
        Console.WriteLine("服務器啓動成功!");
        
        //新建一個check列表用來保存socket信息
        List<Socket> checkRead = new List<Socket>();

        //循環調用檢測
        while(true)
        {
            //把所有的socket信息存入checkRead表中
            checkRead.Clear();
            checkRead.Add(listenfd);
            foreach(ClientState s in clients.Values)
            {
                checkRead.Add(s.socket);
            }

            //Select檢測列表中Socket狀態
            Socket.Select(checkRead, null, null, 1000);

            //判斷Socket狀態
            foreach(Socket s in checkRead)
            {
                //判斷監聽Socket是否可讀,可讀表明有客戶端連接,調用Accept迴應
                //否則處理消息
                if(s==listenfd)
                {
                    //客戶端應答,添加客戶端信息
                    ReadListenfd(s);
                }
                else
                {
                    //接收到客戶端消息,廣播
                    ReadClientfd(s);
                }
            }
        }
    }

    public static void ReadListenfd(Socket listenfd)
    {
        Console.WriteLine("Accept");
        Socket clientfd = listenfd.Accept();
        ClientState state = new ClientState();
        state.socket = clientfd;
        clients.Add(clientfd, state);
    }

    public static bool ReadClientfd(Socket clientfd)
    {
        ClientState state=clients[clientfd];
        //接收部分
        int count = 0;
        try
        {
            count = clientfd.Receive(state.readbuff);
        }
        catch(SocketException e)
        {
            clientfd.Close();
            clients.Remove(clientfd);
            Console.WriteLine("receive socket error" + e.ToString());
            return false;
        }

        //客戶端關閉,receive返回值爲0代表連接斷開
        if(count==0)
        {
            clientfd.Close();
            clients.Remove(clientfd);
            Console.WriteLine("socket close");
            return false;
        }

        //廣播到每一個客戶端
        string recvStr = System.Text.Encoding.Default.GetString(state.readbuff, 0, count);
        Console.WriteLine("receive: " + recvStr);
        //在廣播的消息前加上地址和端口
        string sendstr = clientfd.RemoteEndPoint.ToString() + ":" + recvStr;
        byte[] sendbyte = System.Text.Encoding.Default.GetBytes(sendstr);
        foreach(ClientState s in clients.Values)
        {
            s.socket.Send(sendbyte);
        }
        return true;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章