2013-04-25 92 views
1

我寫了一個由服務器和客戶端組成的程序。服務器製作屏幕截圖桌面,客戶端收到屏幕截圖並在表單上顯示。數據傳輸有問題,我只看到一條小條。我檢查之前發送服務器上的圖像是好的。但是,客戶收到錯誤的圖像。哪裏不對? XAML:只顯示圖片的一小部分

<Window x:Class="TestTCP.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="TestTCP" Height="350" Width="525"> 
<Grid> 
    <Image x:Name="img1" Margin="0"/> 

</Grid> 
</Window> 

代碼C#:

public partial class MainWindow : Window 
    { 
    public MainWindow() 
    { 
     InitializeComponent(); 

     Task rec = new Task(WaitClientQuery); 
     rec.Start(); 

     Task tk = new Task(Send); 
     tk.Start(); 
    } 

    private void Send()//server part. take screen and send image 
    { 
     Bitmap temp = CaptureScreen(true); 
     MemoryStream ms3 = new MemoryStream(); 
     BitmapImage image = new BitmapImage(); 
     byte[] img_byte; 
     try 
     { 
      ((System.Drawing.Bitmap)temp).Save(ms3, System.Drawing.Imaging.ImageFormat.Bmp); 
      image.BeginInit(); 
      ms3.Seek(0, SeekOrigin.Begin); 
      image.StreamSource = ms3; 
      image.EndInit(); 

      JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
      encoder.Frames.Add(BitmapFrame.Create(image)); 
      using (MemoryStream ms = new MemoryStream()) 
      { 
       encoder.Save(ms); 
       img_byte = ms.ToArray(); 
      } 

      try 
      { 

       TcpClient client = new TcpClient("192.168.1.64", 4444); 
       NetworkStream netstream = client.GetStream(); 
       netstream.Write(img_byte, 0, img_byte.Length); 
       netstream.Close(); 
       client.Close(); 
      } 
      catch (Exception) 
      { 

      } 
     } 
     catch (Exception ee) 
     { 

     } 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct CURSORINFO 
    { 
     public Int32 cbSize; 
     public Int32 flags; 
     public IntPtr hCursor; 
     public POINTAPI ptScreenPos; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct POINTAPI 
    { 
     public int x; 
     public int y; 
    } 

    [DllImport("user32.dll")] 
    static extern bool GetCursorInfo(out CURSORINFO pci); 

    [DllImport("user32.dll")] 
    static extern bool DrawIcon(IntPtr hDC, int X, int Y, IntPtr hIcon); 

    const Int32 CURSOR_SHOWING = 0x00000001; 

    public static Bitmap CaptureScreen(bool CaptureMouse) 
    { 
     Bitmap result = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); 
     try 
     { 
      using (Graphics g = Graphics.FromImage(result)) 
      { 
       g.CopyFromScreen(0, 0, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy); 

       if (CaptureMouse) 
       { 
        CURSORINFO pci; 
        pci.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(CURSORINFO)); 

        if (GetCursorInfo(out pci)) 
        { 
         if (pci.flags == CURSOR_SHOWING) 
         { 
          DrawIcon(g.GetHdc(), pci.ptScreenPos.x, pci.ptScreenPos.y, pci.hCursor); 
          g.ReleaseHdc(); 
         } 
        } 
       } 
      } 
     } 
     catch 
     { 
      result = null; 
     } 

     return result; 
    } 

    void WaitClientQuery()//receive data(client) 
    { 
     try 
     { 
      IPAddress ip ; 
      IPAddress.TryParse("192.168.1.64", out ip); 
      TcpListener listener = new TcpListener(ip, 4444); 
      listener.Start(); 
      while (true) 
      { 
       TcpClient client = listener.AcceptTcpClient(); 
       Thread thread = new Thread(new ParameterizedThreadStart(ReadMessage)); 
       thread.IsBackground = true; 
       thread.Start(client); 
      } 
     } 
     catch (Exception ex) 
     { 
     } 
    } 

    void ReadMessage(object obj) 
    { 
     try 
     { 
      TcpClient client = (TcpClient)obj; 
      NetworkStream netstream = client.GetStream(); 
      byte[] arr = new byte[client.ReceiveBufferSize ]; 
      int len = netstream.Read(arr, 0, client.ReceiveBufferSize); 
      if (len > 0) 
      { 
       try 
       { 

        Action act = delegate 
            { 
              MemoryStream strmImg = new MemoryStream(arr); 
              BitmapImage myBitmapImage = new BitmapImage(); 
              myBitmapImage.BeginInit(); 
              myBitmapImage.StreamSource = strmImg; 
              myBitmapImage.EndInit(); 
              img1.Source = myBitmapImage; 
            }; 
        this.Dispatcher.BeginInvoke(act); 

       } 
       catch (Exception ex) 
       { 
        string message = ex.Message; 
       } 

      } 
      netstream.Close(); 
      client.Close(); 
     } 
     catch (Exception ex) 
     { 
     } 
    } 

} 

附:因此,屏幕的程序編譯後: click to view

+0

當你說 「小條」 究竟是什麼意思呢?你的意思是圖像只是一行像素? – 2013-04-25 10:22:58

+0

這個問題的根本原因是'client.ReceiveBufferSize'使用默認值8192,所以你的圖片只能從服務器接收一小部分。 – 2013-04-25 11:20:46

+0

我想爲這個問題+1,因爲許多使用'client.ReceiveBufferSize'在其他地方問題。 – 2013-04-25 15:24:49

回答

1

主根發送和接收特定數據類型我會建議 構建BinaryWriter使用默認值是8192字節導致client.ReceiveBufferSize,所以客戶端將無法接收已經從服務器傳輸足夠的圖像。在我的代碼中,我希望在客戶端看到正確的圖像大小,因此我使用BinaryWriter來傳輸圖像的長度。從客戶端我已經使用BinaryReader來精確讀取圖像的字節數和大小以節省帶寬。希望這有助於

Send方法:

TcpClient client = new TcpClient("192.168.1.64", 4444); 
using (NetworkStream netstream = client.GetStream()) 
{ 
    using (BinaryWriter bw = new BinaryWriter(netstream)) 
    { 
     bw.Write(img_byte.Length); 
     bw.Write(img_byte, 0, img_byte.Length); 
    } 

    client.Close(); 
} 

ReadMessage(object obj)

private void ReadMessage(object obj) 
    { 
     try 
     { 
      byte[] arr = null; 
      TcpClient client = (TcpClient) obj; 
      using (NetworkStream netstream = client.GetStream()) 
      { 
       using (BinaryReader br = new BinaryReader(netstream)) 
       { 
        var arrLen = new byte[4]; 
        br.Read(arrLen, 0, 4); 
        int len = BitConverter.ToInt32(arrLen, 0); 
        if (len > 0) 
        { 
         arr = new byte[len]; 

         int read = 0; 
         while (read != len) 
         { 
          read += br.Read(arr, read, arr.Length - read); 
         } 
        } 
       } 
      } 

      if (arr != null && arr.Length > 0) 
      { 
       try 
       { 

        Action act = delegate 
         { 
          MemoryStream strmImg = new MemoryStream(arr); 
          BitmapImage myBitmapImage = new BitmapImage(); 
          myBitmapImage.BeginInit(); 
          myBitmapImage.StreamSource = strmImg; 
          myBitmapImage.EndInit(); 
          img1.Source = myBitmapImage; 
         }; 
        this.Dispatcher.BeginInvoke(act); 

       } 
       catch (Exception ex) 
       { 
        string message = ex.Message; 
       } 

      } 

      client.Close(); 
     } 
     catch (Exception ex) 
     { 
     } 
    } 
+0

謝謝,我以前也有這個問題。 – 2013-04-26 03:03:01

1

我希望client.ReceiveBufferSize在客戶端上有錯誤信息 我會建議在循環讀取數據。

if(netstream.CanRead) 
{ 
       byte[] myReadBuffer = new byte[1024]; 
       int numberOfBytesRead = 0; 

       do 
     { 
        numberOfBytesRead = netstream.Read(myReadBuffer, 0, myReadBuffer.Length);        
       } 
       while(netstream.DataAvailable); 
} 

和數據保存到列表或MemoryStream的 或可能是更簡單的方法,你的服務器發送的所有數據之前,發送大小

netstream.Write(img_byte.Length); //does not work with NetworkStream 
netstream.Write(img_byte, 0, img_byte.Length); 

和客戶端可以先閱讀它來分配適當的緩衝。 要從NetworkStream

using (BinaryWriter writer = new BinaryWriter(netstream)) 
+0

我就是你製造的。確實,客戶端有錯誤的信息(服務器大小:181021字節)。但是當我使用你的方法來接收字節時,客戶端的緩衝區大小爲:181248字節。我在debbager看到,數組的開始和結束都不是相等的! – 2013-04-25 12:00:58

+0

循環也服務器寫入,tcp將等待接收,所以你可以看到在調試中發生了什麼。我瞭解結束181248多1024表示最後讀取shold返回numberOfBytesRead小於1024 – user2136076 2013-04-25 12:11:17

+0

請參閱下面的代碼帖子以正確地獲取服務器的圖像傳輸大小超過圖像的硬代碼長度。 – 2013-04-25 16:23:32