2012-09-05 48 views
1

因此,通过我的软件,我在网络上发送发现广播,并且接收该广播的每个“客户端”都将通过TCP连接到我。用我所拥有的东西,它似乎工作“OK”,但我觉得必须有更好的方法。我所看到的是一些到我软件的TCP连接被拒绝(我认为),因为我目前正在接受另一个套接字。所以在我目前的版本中,我可以在大约80%的时间内接受套接字。有时会更多,但通常在80%左右。其余的都被我的软件拒绝,我不知道为什么。对我来说这是不可接受的,但我很想改善这个数字。允许数百个TCP客户端在一两秒内连接

这里是一个类我用来接受TCP客户端,并通知有关连接了一个新的socket我的其他类:

public class AsynchronousSocketListener 
{ 
    // Thread signal. 
    public ManualResetEvent allDone = new ManualResetEvent(false); 
    public event EventHandler<ErtdRawDataArgs> ClientConnected; 

    private string bindingIp; 
    public string AddressBind 
    { 
     get { return this.bindingIp; } 
     private set { this.bindingIp = value; } 
    } 

    private int port; 
    public int Port 
    { 
     get { return this.port; } 
     private set { this.port = value; } 
    } 

    private Socket listener; 

    public AsynchronousSocketListener(string bindingIp, int port) 
    { 
     this.bindingIp = bindingIp; 
     this.port = port; 
    } 

    protected void OnClientConnected(string data, IPEndPoint clientEP) 
    { 
     if (this.ClientConnected == null) 
      return; 

     Task.Factory.StartNew(() => 
     { 
      //build args 
      ErtdRawDataArgs args = new ErtdRawDataArgs(Encoding.Default.GetBytes(data)); 
      args.Source = string.Format("{0}:{1}", clientEP.Address.ToString(), clientEP.Port); 
      this.ClientConnected(this, args); 
     }); 
    } 

    public void Close() 
    { 
     if (this.listener == null || !this.listener.Connected) 
      return; 

     this.listener.Shutdown(SocketShutdown.Both); 
     this.listener.Close(); 
    } 

    public void StartListening() 
    { 
     Task.Factory.StartNew(() => 
     { 
      // Data buffer for incoming data. 
      byte[] bytes = new Byte[1024]; 

      // Establish the local endpoint for the socket. 
      IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(this.bindingIp), this.port); 

      // Create a TCP/IP socket. 
      listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

      // Bind the socket to the local endpoint and listen for incoming connections. 
      try 
      { 
       listener.Bind(localEndPoint); 
       int maxConnections = (int)SocketOptionName.MaxConnections; 
       listener.Listen(maxConnections); 

       while (true) 
       { 
        // Set the event to nonsignaled state. 
        allDone.Reset(); 

        // Start an asynchronous socket to listen for connections. 
        listener.BeginAccept(
         new AsyncCallback(AcceptCallback), 
         listener); 

        // Wait until a connection is made before continuing. 
        allDone.WaitOne(); 
       } 

      } 
      catch (Exception e) 
      { 
       Console.WriteLine(e.ToString()); 
      } 
     }); 
    } 

    public void AcceptCallback(IAsyncResult ar) 
    { 
     // Signal the main thread to continue. 
     allDone.Set(); 

     // Get the socket that handles the client request. 
     Socket listener = (Socket) ar.AsyncState; 
     Socket handler = listener.EndAccept(ar); 

     // Create the state object. 
     StateObject state = new StateObject(); 
     state.workSocket = handler; 
     handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
      new AsyncCallback(ReadCallback), state); 
    } 

    public void ReadCallback(IAsyncResult ar) 
    { 
     String content = String.Empty; 

     // Retrieve the state object and the handler socket 
     // from the asynchronous state object. 
     StateObject state = (StateObject) ar.AsyncState; 
     Socket handler = state.workSocket; 

     // Read data from the client socket. 
     int bytesRead = handler.EndReceive(ar); 

     if (bytesRead > 0) { 
      // There might be more data, so store the data received so far. 
      state.sb.Append(Encoding.ASCII.GetString(
       state.buffer,0,bytesRead)); 

      // Check for end-of-file tag. If it is not there, read 
      // more data. 
      content = state.sb.ToString(); 
      OnClientConnected(content, handler.RemoteEndPoint as IPEndPoint); 

      //close socket 
      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 
     } 
    } 
} 

有什么办法改善这种代码或者是有一起完全不同的东西在几乎同一时间改善我接受TCP连接的结果?

+0

您使用异步接受不正确:您正在等待它完成。您可以改为同步。通过等待一个事件,你会得到两个世界中最糟糕的,没有什么好处。 – usr

回答

1

那么,您在接受连接之前和连接“已建立”之间有一段时间,然后才能接受其他连接。使用诸如等待手柄之类的东西可能相当缓慢。

重新读取您的代码后,从概念上讲,您可以接受另一个连接的点是您调用EndAccept时。看起来您正在设置事件,然后您致电EndAccept这意味着BeginAccept可以在EndAccept之前调用,并且在先前调用EndAccept之前可以接受另一个连接。我不知道这是否是一个问题 - 据我所知,这是合法的。但是,你可以简化你的代码,以避免事件,只是在当前链的下一个BeginAccept接受并确保EndAccept先下一BeginAccept

我要做的就是链的下一个从当前内接受接受被调用。例如:

listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
listener.Bind(new IPEndPoint(IPAddress.Any, 62000)); 
listener.Listen(1000); 
listener.BeginAccept(OnAccept, listener); 

private void OnAccept(IAsyncResult ar) 
{ 
    Socket listener = (Socket)ar.AsyncState; 
    Socket socket = listener.EndAccept(ar); 
    listener.BeginAccept(OnAccept, listener); 
    socket.BeginReceive(new byte[10], 0, 10, 0, (arReceive) => socket.EndReceive(arReceive), null); 
} 
当然

,我使用BeginAcceptSocket这里;但这个概念将与BeginAccept一样...

这使你不必启动新Task,从创建等待句柄这是约50倍慢释放是lock,因为他们是跨进程 - 这使您免于接受之间的“巨大”暂停。

+0

我不是最好的插座,所以我不完全得到你所说的。为你的例子添加更多细节,甚至是我的例子来解释你的意思? – Travyguy9