日期:2014-05-18  浏览次数:20788 次

用thread开启线程和异步接收socket的疑问?
private Socket socket;
private Socket acceptSocket; 
protected void Listen()
  {
  socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  socket.Bind(new IPEndPoint(IPAddress.Any, 2000));
  socket.Listen(0);
  while (true)
  {
  //acceptSocket = socket.Accept();
  //Thread thread = new Thread(new ThreadStart(BeginTempSocket));
  //thread.Start();

  //下面使用非阻塞式来接收客户端的请求,程序会有点卡,并且会报outofMemory的错误
  socket.BeginAccept(new AsyncCallback(AsyncBeginTempSocket), socket);
  }
  }
protected void AsyncBeginTempSocket(IAsyncResult ar)
  {
  Socket s = (Socket)ar.AsyncState;
  acceptSocket = s.EndAccept(ar);
  ............接收数据
  }
protected void BeginTempSocket()
  {
  ............接收数据
  }
如上的代码:如果使用acceptSocket = socket.Accept();同步接收客户端,然后开启thread来接收数据,程序正常,很流畅;
但是如果使用socket.BeginAccept(new AsyncCallback(AsyncBeginTempSocket), socket);异步接收socket客户端的话,程序有点卡,并且连接了几次,就报outofMemory的错误了!具体的接收数据的代码都是一样的。

为什么呢?是不是异步的地方有哪里写得不对啊?
谢谢!

------解决方案--------------------
BeginAccept很快就返回了。在循环中调用它,会造成很多很多很多个连接等待,不是好的选择。
由于OS会提供排队缓冲区,一般用一个线程进行Accept就可以了。连接后的具体通信再由不同的线程来处理(或进行异步操作)。
C# code

void Listen()
{
  while (true)
  {
    Socket s = socket.Accept();
    ThreadPool.QueueUserWorkItem(Worker, s);
  }
}
void Worker(object state)
{
   Socket soket = state as Socket;
   //...
}

------解决方案--------------------
使用tcplistener和tcpclient会简单一些,而且可以使用到IOCP。

就算如你的代码那样使用sockey服务的主程序,大致(按照你的代码)就是这样:
C# code
protected void Listen()
{
  socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  socket.Bind(new IPEndPoint(IPAddress.Any, 2000));
  socket.Listen(int.MaxValue);
  socket.BeginAccept(new AsyncCallback(AsyncAcceptSocket), null);
}