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

游戏研发 专栏收录该内容
9 篇文章 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<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;
    }
}

 

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页

打赏

qq_15029743

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值