以下是Server的代碼,最近在學習網路編程,一直在思考如何開發出高並發的伺服器端。經常聽說對伺服器描述為同時10000個串連,就在想能否用C#寫個這樣的伺服器出來呢。同步編程模型就不考慮了,來看看TcpListener的非同步編程模型能否滿足需求。
public partial class COMService {private int maxLink = 100000;private int currentLinked; private ManualResetEvent tcpClientConnected = new ManualResetEvent(false);public void Start() {Thread thread = new Thread(new ParameterizedThreadStart(ShowStat));thread.IsBackground = true;thread.Start();TcpListener server = new TcpListener(new System.Net.IPEndPoint(0, 8090));server.Start(100);tcpClientConnected.Reset();IAsyncResult result = server.BeginAcceptTcpClient(new AsyncCallback(Acceptor), server);tcpClientConnected.WaitOne();}private void ShowStat(object o) {while (true) {lock (typeof(COMService)) {Console.WriteLine("當前串連數:" + currentLinked + "/" + maxLink);}Thread.Sleep(2000);}}private void Acceptor(IAsyncResult o) {TcpListener server = o.AsyncState as TcpListener;Debug.Assert(server != null);TcpClient client = null;try {client = server.EndAcceptTcpClient(o);System.Threading.Interlocked.Increment(ref currentLinked);} catch {}IAsyncResult result = server.BeginAcceptTcpClient(new AsyncCallback(Acceptor), server);if (client == null) {return;} else {Thread.CurrentThread.Join();}Close(client);}private void Close(TcpClient client) {if (client.Connected) {client.Client.Shutdown(SocketShutdown.Both);}client.Client.Close();client.Close();System.Threading.Interlocked.Decrement(ref currentLinked);}}}
以下是Client的代碼:
public class ClientPool {private static List<TcpWork> clients = new List<TcpWork>();private static int freeCount;private static int workCount;private static int maxAllowed =2;private static int minClients = 2;/// <summary>/// create new instance/// </summary>private ClientPool() {}private static ClientPool instance;private static readonly object syncInstanceObj = new object();public static ClientPool Singleton {get {if (instance == null) {lock (syncInstanceObj) {if (instance == null) {instance = new ClientPool();}}}return instance;}}private static readonly object syncObj = new object();public TcpWork GetClient() {try {TcpWork work = new TcpWork();work.Connect("127.0.0.1", 8090);work.LingerState = new LingerOption(false, 3);work.IsWork = true;work.Expired = false;workCount++;lock (syncObj) {clients.Add(work);}Console.WriteLine(workCount);return work;} catch (Exception ex){Console.WriteLine(ex.Message);return null;}}}
Client類比多線程並發:
class Program {static void Main(string[] args) {for (int i = 0; i < 1000; i++) {ThreadPool.QueueUserWorkItem(new WaitCallback(Work), null);}Console.ReadKey();}private static void Work(object o) {ClientPool.Singleton.GetClient();}}
從這個編程模型可以看出,高並發的伺服器不光需要滿足有多少個並發串連數,每秒建立多少個串連數也是個重要指標~~
實際運行上看看,TcpListener每秒大概能建立兩個串連,其他的串連會被拒絕,保持的長串連數1000的樣子。很明顯,TcpListener要被哢嚓掉了~~
注意,以上代碼僅僅是用來測·試串連用的,這種寫法會導致伺服器端的串連無法釋放~~~~