IO完成端口是如何做的
长连接的简单模型大概是这样的
- C# code
private int _port = 6868; private const int _maxPacket = 64; private TcpListener _tcpl = null; public string userip; public Hashtable _transmit_tb = new Hashtable(); static void Main(string[] args) { Listen l = new Listen(); try { l.startup(); } catch (Exception) { } } public void startup() { IPAddress _ip = Dns.GetHostAddresses(Dns.GetHostName())[0]; _tcpl = new TcpListener(_ip, _port); _tcpl.Start(); Console.WriteLine(string.Format("the server ip is {0},and the port is {1}", _ip, _port)); Console.WriteLine("server has been started,is listening..."); while (true) { byte[] packetBuff = new byte[_maxPacket]; Socket newClient = _tcpl.AcceptSocket(); IPEndPoint ip = (IPEndPoint)newClient.RemoteEndPoint; //userip = ip.Address.ToString().TrimEnd() + ":" + ip.Port; userip = ip.Address.ToString().TrimEnd(); if (_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(userip)) { _transmit_tb.Remove(userip); _transmit_tb.Add(userip, newClient); } else _transmit_tb.Add(userip, newClient); string svrlog = string.Format("new ip {0} at {1} is connected,current online number is {2}", userip + ":" + ip.Port, DateTime.Now, _transmit_tb.Count); Console.WriteLine(svrlog); Thread clientthread = new Thread(new ParameterizedThreadStart(threadfun)); clientthread.Start(userip); clientthread.IsBackground = true; Thread.Sleep(200); } } private void threadfun(object obj) { Socket clientsocket = _transmit_tb[obj] as Socket; while (true) { try { if (clientsocket == null || clientsocket.Available < 1) { Thread.Sleep(300); continue; } byte[] _cmdBuff = new byte[128]; int size = clientsocket.Receive(_cmdBuff); //在这里处理收到的数据 //向客户端发送数据 clientsocket.Send(_cmdBuff); } catch (SocketException) { _transmit_tb.Remove(obj); clientsocket.Close(); Thread.CurrentThread.Abort(); } } }
在主线程里监听客户端连接请求,然后每个连接到服务器的用户都建立一个线程,在这个线程里再死循环收客户发来的数据包,做处理以后再回客户端数据包,这种模式显然用户很多的时候是不行的,太耗服务器资源。
请高手帮忙把这段代码改成IO完成端口的,可以接收同时5000人以上用户的连接。
请给详细代码,写上注释。
[解决办法]
http://topic.csdn.net/t/20040512/08/3056877.html
[解决办法]
其实C#的很多异步操作已经使用了IO Complemention,你只要简单的BeginReceive/EndReceive就可以了。.Net内部会帮你把IO Complemtion发送到线程池并调用你提供的回调函数。
比如下面的代码。
在实验中保持Server运行,同时运行多次Client,你可以发现.Net并不一定需要多个线程来服务多个客户,在保持快速响应的同时,尽可能复用可用线程(可能最终一个就够了):
- C# code
// Server.csclass Server{ static void Main(string[] args) { TcpListener listener = new TcpListener(IPAddress.Any, 4567); listener.Start(); while (true) { Socket socket = listener.AcceptSocket(); StateObject so = new StateObject() { socket = socket }; so.socket.BeginReceive(so.buffer, so.offset, StateObject.BUFFER_SIZE - so.offset, SocketFlags.None, AsyncCallback, so); } } static void AsyncCallback(IAsyncResult ar) { Console.WriteLine("AsyncCallBack in managed thread " + Thread.CurrentThread.ManagedThreadId); StateObject so = ar.AsyncState as StateObject; int read = 0; try { read = so.socket.EndReceive(ar); so.offset += read; } catch (SocketException se) { Console.WriteLine(se.Message); } if (read == 0) { string msg = Encoding.UTF8.GetString(so.buffer, 0, so.offset); Console.WriteLine(msg); } else { so.socket.BeginReceive(so.buffer, so.offset, StateObject.BUFFER_SIZE - so.offset, SocketFlags.None, AsyncCallback, so); } } public class StateObject { public Socket socket = null; public const int BUFFER_SIZE = 64*1024; public byte[] buffer = new byte[BUFFER_SIZE]; public int offset = 0; }}