C#中稳定的socket收发实现:agsxmpp的ClientSocket实现

来源:互联网 发布:长春网络营销策划 编辑:程序博客网 时间:2024/06/16 22:39

在xmpp协议中规定 从客户端到服务器端的通讯方式是一个持续的tcp连接或者是http的polling,后者作为备选,一般也是使用前者。

socket编程可简可难,可好可烂。在C#中,因为CLR维持了工作组线程,异步调用的语法也相对简单(好像是最简单的了-_-!),所以写出稳定的socket收发也变的更容易了。agsxmpp的ClientSocket实现大概可分步为:

1.一个 tcp连接
2.一个初始的连接异步调用
3.连接异步调用完成后接收异步调用开始,并且在完成的时候不断回调自身实现循环,但是这个循环不保证是在同一个线程内部的
4.发送异步调用在连接之后断开之前都可以进行

总之对接收而言是一个 socket 资源 两个 工作端 线程资源。在这里资源这个理解很重要,因为实际上每次接收线程回调后并不一定还是原来的线程继续执行接收方法。有可能,当发送方法不工作 ,而接收线程又未启动的话,实质上是没有 线程在对 socket做任何事情的。socket作为网络资源 与 线程作为 CPU 资源事实上是分离了。以前很难这样想问题,因为线程的开发相当复杂,而现在可以异步调用,交由工作线程来做。

以下是receive方法以及其完成回调,可以看到在EndReceive方法中判断是否结束如不是则回调Receive方法,循环下去。

  /// <summary>
  /// Read data from server.
  /// </summary>
  private void Receive()
  {   
   m_NetworkStream.BeginRead(m_ReadBuffer, 0, BUFFERSIZE, new AsyncCallback(EndReceive), null);
  }

  private void EndReceive(IAsyncResult ar)
  {
   try
   {
    int nBytes;
    nBytes = m_NetworkStream.EndRead(ar);
    if( nBytes > 0 )
    {
                    // uncompress Data if we are on a compressed socket
                    if (m_Compressed)
                    {                       
                        byte[] buf = Decompress(m_ReadBuffer, nBytes);
                        base.FireOnReceive(buf, buf.Length);
                    }
                    else
                    {
                        //Console.WriteLine("Socket OnReceive: " + System.Text.Encoding.UTF8.GetString(m_ReadBuffer, 0, nBytes));
                        // Raise the receive event
                        base.FireOnReceive(m_ReadBuffer, nBytes);
                    }
     // Setup next Receive Callback
     if (this.Connected) this.Receive();
    }
    else
    {
     Disconnect();
    }
   }
   catch(ObjectDisposedException)
   {
    //object already disposed, just exit
    return;
   }
   catch (System.IO.IOException ex)
   {
    Console.WriteLine("/nSocket Exception: " + ex.Message);
    Disconnect();
   }
  }

Receive 方法 在 EndConnection方法结束的时候即开始回调:

  private void EndConnect(IAsyncResult ar)
  {
   try
   {    
    // pass connection status with event
    _socket.EndConnect(ar);
    m_Stream = new NetworkStream(_socket, false);
  
    m_NetworkStream = m_Stream;
#if SSL || MONOSSL
    if (m_SSL)
     InitSSL();
#endif
    FireOnConnect();    
    
    // Setup Receive Callback
    this.Receive();

   }
   catch (Exception ex)
   {
                base.FireOnError(ex);    
   }
  }

这个是send方法:

  public override void Send(byte[] bData)
  {          
            base.FireOnSend(bData, bData.Length);

            //Console.WriteLine("Socket OnSend: " + System.Text.Encoding.UTF8.GetString(bData, 0, bData.Length));

            // compress bytes if we are on a compressed socket
            if (m_Compressed)
            {
                bData = Compress(bData);               
            }

            // .NET 2.0 SSL Stream issues when sending multiple async packets
            // http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=124213&SiteID=1
            if (m_PendingSend)
                m_SendQueue.Enqueue(bData);
            else
            {              
                m_PendingSend = true;
                m_NetworkStream.BeginWrite(bData, 0, bData.Length, new AsyncCallback(EndSend), null);
            }          
  }

原创粉丝点击