2016-08-11 259 views
1

我有兩個c#服務器套接字一些奇怪的問題。C# - 異步服務器vs同步服務器 - 套接字

我有2臺服務器。一個是異步的,另一個是同步的。我也有Android的客戶端發送圖片到這臺服務器。

同步服務器:

Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

public void Start() 
{ 
    byte[] bytes = new Byte[1024000]; 
    String content = String.Empty; 

    IPAddress ipAddress = IPAddress.Parse("192.168.1.2"); 
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 53100); 

    try 
    { 
     listener.Bind(localEndPoint); 
     listener.Listen(10); 

     while (true) 
     { 
      //// Program is suspended while waiting for an incoming connection. 
      Socket handler = listener.Accept(); 
      data = null; 

      // An incoming connection needs to be processed. 
      while (true) 
      { 
       bytes = new byte[1024000]; 
       int bytesRec = handler.Receive(bytes); 
       strBuilder.Append(Encoding.ASCII.GetString(bytes, 0, bytesRec)); 
       if (strBuilder.Length > 1) 
       { 
        content = strBuilder.ToString(); 
        byte[] xdata = Convert.FromBase64String(content); 
        using (var mStream = new MemoryStream(xdata, 0, xdata.Length)) 
        { 
         pictureBox1.Image = Image.FromStream(mStream, true); 
        } 
       } 
      } 
      byte[] msg = Encoding.ASCII.GetBytes(data); 

      handler.Send(msg); 
      handler.Shutdown(SocketShutdown.Both); 
      handler.Close(); 
     } 

    } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
    } 
} 

private void Form1_Load(object sender, EventArgs e) 
{ 
    thr = new Thread(new ThreadStart(Start)); 
    thr.Start(); 
} 

異步服務器:

public void StartListening() 
     { 
      listener.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 53100)); 
      listener.Listen(1); 
      allDone.Reset(); 
      listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
     } 

     public void AcceptCallback(IAsyncResult ar) 
     { 
      Socket listener = (Socket)ar.AsyncState; 
      Socket handler = listener.EndAccept(ar); 

      StateObject stateObj = new StateObject(); 
      stateObj.clientSocket = handler; 
      handler.BeginReceive(stateObj.buffer, 0, StateObject.buffSize, 0, 
       new AsyncCallback(ReadCallback), stateObj); 

      listener.BeginAccept(new AsyncCallback(AcceptCallback), listener); 
     } 

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

      StateObject stateObj = (StateObject)ar.AsyncState; 
      Socket handler = stateObj.clientSocket; 

      SocketError errorCode; 
      int bytesRead = handler.EndReceive(ar, out errorCode); 
      if (errorCode != SocketError.Success) 
      { 
       bytesRead = 0; 
      } 

      if (bytesRead > 0) 
      { 
       stateObj.strBuilder.Append(Encoding.ASCII.GetString(stateObj.buffer, 0, bytesRead)); 
       handler.BeginReceive(stateObj.buffer, 0, stateObj.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), stateObj); 
      } 
      else 
      { 
       if (stateObj.strBuilder.Length > 1) 
       { 
        content = stateObj.strBuilder.ToString(); 

        Debug.WriteLine(content); 
        byte[] data = Convert.FromBase64String(content); 
        using (var mStream = new MemoryStream(data, 0, data.Length)) 
        { 
         pictureBox1.Image = Image.FromStream(mStream, true); 
        } 

        recImage = (Bitmap)pictureBox1.Image; 
        imgImage = new Image<Bgr, Byte>(recImage); 
        imageBox1.Image = imgImage; 

        while (imageBox1.Image != null) 
        { 
         SURFDetectionAndGUIUpdate(this, new EventArgs()); 
        } 
        string xname = name.ToString(); 
        Send(handler, xname); 
       } 
      } 
     } 

     private void Send(Socket handler, String data) 
     { 
      byte[] byteData = Encoding.ASCII.GetBytes(data); 

      handler.BeginSend(byteData, 0, byteData.Length, 0, 
       new AsyncCallback(SendCallback), handler); 
     } 

     private void SendCallback(IAsyncResult ar) 
     { 
      try 
      { 
       Socket handler = (Socket)ar.AsyncState; 
       int bytesSent = handler.EndSend(ar); 
       handler.Shutdown(SocketShutdown.Both); 
       handler.Close(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
     } 

的問題是,當我發送圖片從客戶端同步服務器一切正常,並且服務器接收到它,但如果我從發送圖片同一個客戶端到異步服務器它不會收到它。

+0

你應該能夠縮小事情失敗的部分。 'AcceptCallback'曾經被調用過嗎? ReadCallback被調用過嗎?我看到的一件事是,你從另一個線程設置'pictureBox1.Image'而不是UI線程。 –

+0

問題看起來像這樣:當我用android應用拍照並將其發送給異步服務器時,服務器會收到圖像,但前提是關閉客戶端應用程序。如果我使用同步服務器,則不會發生這種情況。這對我來說很奇怪,因爲客戶端應用程序在這兩種情況下都是相同的 – SimpleCoder

+0

這很有道理,在同步客戶端中,您立即嘗試將數據轉換爲單個「Receive」後的圖像,而在異步服務器中,只處理數據客戶端斷開連接後發生錯誤(if(bytesRead> 0)''else'')。 –

回答

2

當前,您的同步服務器嘗試從第一個Receive的數據創建一個位圖,異步服務器會等待,直到客戶端嘗試從數據創建位圖之前斷開連接。

TCP 數據,這意味着您可以在數據到達時按發送順序讀取數據,但發送1000個字節並不意味着您將一次收到1000個字節。您甚至可以通過一個Receive操作接收來自兩條不同消息的數據。您發送的數據越多,發送數據的次數越多,發生此效應的可能性越大。

在你提到的客戶端將發送多張圖片,讓你繼續之前,你應該決定要如何確定接收到第一個圖像時,當第二圖像數據開始評論:

  • 您可以選擇讓客戶端在發送每個圖像後斷開連接,如異步服務器當前所期望的那樣
  • 在發送圖像數據本身之前,您可以選擇首先發送圖像的字節數。確保尺寸本身以固定長度進行編碼。這可以防止您必須始終重新連接,並且還允許您預先確定接收緩衝區的大小。
  • 或者您可以使用base64範圍外的字節分隔數據,但這需要掃描接收的數據
+0

我發送圖片從android應用程序到服務器作爲Base64String。我想要實現的是這樣的情況:我在客戶端上拍照,發送給服務器,然後服務器應該接收到這個圖像,並將響應發送給客戶端,之後我想發送第二張圖片等等。目前的情況很奇怪,因爲如果我刪除了在android客戶端上接收到響應部分,並且如果我發送picrure,服務器收到它而沒有關閉android應用 – SimpleCoder

+0

任何想法?一點建議 ? – SimpleCoder

+0

服務器如何知道它是否收到第一張圖像?這正是我在我的回答中試圖解釋的。 –