不使用异步多线程技术,同步程序如何改善C/S架构呢?
答案是在同步程序中添加判断,判断想要进行的操作是否可以完成。
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 listenfdprivate static Socket listenfd;//连接服务端的客户端列表(使用字典是为了方便查找)private static Dictionary clients =new Dictionary();public static void Main(string[] args){Console.WriteLine("Hello World!");//创建监听Socketlistenfd = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//注册BindIPAddress 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中检测数据,同样是一种浪费。从性能角度考虑,还有不小的改进空间。
下一篇:线性动态规划问题