Unity多路复用服务器端(Select)

在网络游戏中,多路复用的方式是最常见的服务器端解决方案,程序结构如图:

Unity多路复用服务器端(Select)_第1张图片

 程序代码:

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 clients=new Dictionary();
    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 checkRead = new List();

        //循环调用检测
        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;
    }
}

 

你可能感兴趣的:(游戏研发)