Unity3D网络游戏0.4

状态检测 Poll

 不使用异步多线程技术,同步程序如何改善C/S架构呢?
 答案是在同步程序中添加判断,判断想要进行的操作是否可以完成。

Socket.Poll 方法

 Poll方法的原型如下:

public bool Poll(
	int microSeconds,
	SelectMode mode
)
参数 说明
microSeconds 等待回应的时间(ms)
mode Read /Write /Error

 Poll方法会检擦Socket的状态.
 如果指定mode参数为SelectMode.SelectRead则可确定Socket是否可读,指定参数为SelectMode.SelectWrite确定参数是否可写,指定参数为SelectMode.SelectError可以检测错误条件。
 Poll将在指定的时间段内阻止执行,若在某一时刻检测的状态为true则返回,否则将一直检测完整个时间段。如果要一直检测可将microSeconds设置为-1,如果希望不阻塞可将microSeconds设置为0。

同步客户端

 使用Poll方法开发同步聊天客户端,代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using UnityEngine;
using UnityEngine.UI;

public class Echo : MonoBehaviour
{
   private Socket socket;
   public InputField inputField;
   public Text text;
   private byte[] readBuff = new byte[1024];
   private string recvStr = "";
   
   public void Connection()
   {
      socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
      //其实没有连接上Socket也无法聊天,所以此处写同步方法
      socket.Connect("127.0.0.1", 8888);
   }

   public void Send()
   {
      string sendStr = inputField.text;
      byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);
      //当可用发消息时才发消息
      if (socket.Poll(0, SelectMode.SelectWrite))
         socket.Send(sendBytes);
   }

   public void Update()
   {
      if (socket == null)
         return;
      //当有消息可读时才读消息
      if (socket.Poll(0, SelectMode.SelectRead))
      {
         byte[] readBuff = new byte[1024];
         int count = socket.Receive(readBuff);
         string readStr = System.Text.Encoding.Default.GetString(this.readBuff, 0, count);
         text.text = readStr;
      }
   }
}

同步服务端

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
public class ClientState
{
    public Socket socket;
    public byte[] readBuff = new byte[1024];
}

class MainClass
{
    //监听Socket listenfd
    private static Socket listenfd;
    //连接服务端的客户端列表(使用字典是为了方便查找)
    private static Dictionary<Socket, ClientState> clients =
        new Dictionary<Socket, ClientState>();

    public static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");
        //创建监听Socket
        listenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //注册Bind
        IPAddress ipAdr = IPAddress.Parse("127.0.0.1");
        IPEndPoint ipEp = new IPEndPoint(ipAdr, 8888);
        listenfd.Bind(ipEp);
        //设置并开始监听
        listenfd.Listen(0);
        Console.WriteLine("[服务器]启动成功");
        while (true)
        {
            if (listenfd.Poll(0, SelectMode.SelectRead))
            {
                ReadListenfd(listenfd);
            }

            foreach (ClientState cs in clients.Values)
            {
                Socket clientfd = cs.socket;
                if (clientfd.Poll(0, SelectMode.SelectRead))
                {
                    if (!ReadClientfd(clientfd))
                    {
                        break;
                    }
                }
            }
        }
        System.Threading.Thread.Sleep(1);
    }
    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 SocketExeception:"+e.ToString());
            return false;
        }
        if (count == 0)
        {
            clientfd.Close();
            clients.Remove(clientfd);
            return false;
        }

        string recvStr = System.Text.Encoding.Default.GetString(state.readBuff, 0, count);
        Console.WriteLine("Receive"+recvStr);
        string sendStr = clientfd.RemoteEndPoint.ToString() + ":" + recvStr;
        byte[] sendBytes = System.Text.Encoding.Default.GetBytes(sendStr);
        foreach (ClientState cs in clients.Values)
        {
            cs.socket.Send(sendBytes);
        }

        return true;
    }
}

 尽管逻辑清晰,但Poll 服务端的弊端也很明显,若没有收到客户端数据,服务端也一直在循环,浪费了CPU。Poll客户端也是同理,没有数据的时候还一直在Update中检测数据,同样是一种浪费。从性能角度考虑,还有不小的改进空间。

你可能感兴趣的:(Unity网络游戏,网络,java,开发语言)