IO完成端口是如何做的

西江 2012-03-12 08:36:10
长连接的简单模型大概是这样的

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人以上用户的连接
请给详细代码,写上注释
...全文
139 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
gomoku 2012-03-13
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 gomoku 的回复:]
其实C#的很多异步操作已经使用了IO Complemention,你只要简单的BeginReceive/EndReceive就可以了。.Net内部会帮你把IO Complemtion发送到线程池并调用你提供的回调函数。
[/Quote]
请更正我的错别字:)
IO Completion
gomoku 2012-03-13
  • 打赏
  • 举报
回复
其实C#的很多异步操作已经使用了IO Complemention,你只要简单的BeginReceive/EndReceive就可以了。.Net内部会帮你把IO Complemtion发送到线程池并调用你提供的回调函数。

比如下面的代码。
在实验中保持Server运行,同时运行多次Client,你可以发现.Net并不一定需要多个线程来服务多个客户,在保持快速响应的同时,尽可能复用可用线程(可能最终一个就够了):

// Server.cs
class 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;
}
}


// Client.cs
class Client
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(Sender, "Hello world ");
ThreadPool.QueueUserWorkItem(Sender, "nihao ");
ThreadPool.QueueUserWorkItem(Sender, "Bonjour ");

Console.ReadLine();
}

static void Sender(object state)
{
TcpClient tcp = new TcpClient("localhost", 4567);
Random random = new Random( state.GetHashCode() );
using (NetworkStream stream = tcp.GetStream())
{
for (int i = 0; i < 10; i++)
{
byte[] bytes = Encoding.UTF8.GetBytes( state as string);
stream.Write(bytes, 0, bytes.Length);
Thread.Sleep(random.Next(5 * 1000));
}
}
}
}
nonocast 2012-03-13
  • 打赏
  • 举报
回复
道理是一样的,关键是要理解异步投递的模型
Managed I/O Completion Ports (IOCP)
西江 2012-03-13
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 nonocast 的回复:]

http://topic.csdn.net/t/20040512/08/3056877.html
[/Quote]你给这个,大概看了一样,是VC的?
gomoku 2012-03-13
  • 打赏
  • 举报
回复
Server.cs底下不是有一个client.cs吗?
西江 2012-03-13
  • 打赏
  • 举报
回复
gomoku大哥,你给这个代码,在服务器端是收数据的,那发数据是怎么发的,再补充下哦

111,126

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧