2011-04-30 40 views
1

我正在創建一個遠程桌面程序,因此我開發了一個類,它獲取客戶端計算機的快照並將每個圖像以字節數組格式發送到服務器。然後服務器讀取這些字節並將該流轉換爲System.Drawing.Image類型。但是Image.FromStream需要很長時間。每當我突破這條線在它下面卡住。在該行代碼之後沒有異常被拋出,沒有任何事情發生。需要更快地實現Image.FromStream以實時顯示圖像

線引起的問題:

StreamingData(客戶端,新DataEventArgs(Image.FromStream(流,假的,假的)));

的完整代碼

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Net; 
using System.Net.Sockets; 
using System.Windows.Forms; 
using System.Drawing; 
namespace Simply_Remote_Desktop_Library 
{ 
    public sealed class RemoteDesktopListener 
    { 
     private TcpListener listner; 
     private TcpClient client; 
     public delegate void ConnectedEventHandler(TcpClient sender, EventArgs e); 
     public event ConnectedEventHandler Connected; 
     public delegate void IncommingDataEventHandler(TcpClient sender, DataEventArgs e); 
     public event IncommingDataEventHandler StreamingData; 
     public delegate void ConnectionEndedEventHandler(RemoteDesktopListener sender, EventArgs e); 
     public event ConnectionEndedEventHandler ConnectionEnded; 
     /// <summary> 
     /// Constructor (+1 Overloads) 
     /// </summary> 
     /// <param name="port">The port to listen for incoming connections.</param> 
     /// <param name="host_ip">The IP address of the client computer.</param> 
     public RemoteDesktopListener(int port, string host_ip) 
     { 
      IPAddress addr; 
      if (IPAddress.TryParse(host_ip, out addr)) 
      { 
       if (port > 0 || port < 65535) 
       { 
        listner = new TcpListener(addr, port); 
       } 
       else if (port < 0 || port > 65535) 
       { 
        throw new RemoteDesktopException(new ArgumentOutOfRangeException("port")); 
       } 
      } 
      else 
      { 
       throw new RemoteDesktopException("Error: Invalid IP address in string format. Make sure it is in the right format."); 
      } 
     } 
     /// <summary> 
     /// Constructor (+1 Overloads) 
     /// </summary> 
     /// <param name="port">Port for server to listen for incoming connections.</param> 
     /// <param name="host_ip">Ip address of client.</param> 
     public RemoteDesktopListener(int port, IPAddress host_ip) 
     { 
      if (port > 0 && port < 65535) 
      { 
       listner = new TcpListener(host_ip, port); 
      } 
      else if (port < 0 && port > 65535) 
      { 
       throw new RemoteDesktopException("Error: Port number invalid! Range is from 0 - 65535."); 
      } 
     } 
     /// <summary> 
     /// Starts the listening process and establishes a connection to a client. 
     /// </summary> 
     public void BeginListening() 
     { 
      if (listner == null) 
      { 
       throw new RemoteDesktopException(new NullReferenceException()); 
      } 
      else if (listner != null) 
      { 
       byte[] bytes = new byte[204800]; 
       bool connected = false; 
       listner.Start(); 
       //int i; 
       while (true) 
       { 
        client = listner.AcceptTcpClient(); 
        if (connected == false) 
        { 
         Connected(client, new EventArgs()); 
         connected = true; 
        } 
        NetworkStream stream = client.GetStream(); 
        while (stream.DataAvailable == true) 
        { 

         StreamingData(client, new DataEventArgs(Image.FromStream(stream, false, false))); 
        } 
        client.Close(); 
        ConnectionEnded(this, new EventArgs()); 
       } 

      } 
      return; 
     } 
     /// <summary> 
     /// Starts listening for incoming connection requests. 
     /// </summary> 
     /// <param name="backlog">Maximum number of pending connection</param> 
     public void BeginListening(int backlog) 
     { 
      if (listner == null) 
      { 
       throw new RemoteDesktopException(new NullReferenceException()); 
      } 
      else if (listner != null) 
      { 
       //byte[] bytes = new byte[204800]; 
       bool connected = false; 
       listner.Start(backlog); 
       //int i; 
       while (true) 
       { 
        client = listner.AcceptTcpClient(); 
        if (connected == false) 
        { 
         Connected(client, new EventArgs()); 
         connected = true; 
        } 
        NetworkStream stream = client.GetStream(); 
        while (stream.DataAvailable == true) 
        { 

         StreamingData(client, new DataEventArgs(Image.FromStream(stream, false, false))); 
        } 
        client.Close(); 
        ConnectionEnded(this, new EventArgs()); 
       } 

      } 
      return; 
     } 
     public void StopListening() 
     { 
      client.Close(); 
      listner.Stop(); 
     } 
     /// <summary> 
     /// Returns the System.Net.Sockets.Socket of the current session. 
     /// </summary> 
     public Socket Socket 
     { 
      get 
      { 
       return listner.Server; 
      } 
     } 
     ~RemoteDesktopListener() 
     { 
      client.Close(); 
      listner.Stop(); 
      ConnectionEnded(this, new EventArgs()); 
     } 

    } 
    public sealed class RemoteDesktopClient 
    { 
     private TcpClient client; 
     private Timer timer; 
     private Bitmap bitmap; 
     private System.Drawing.Imaging.PixelFormat format; 
     private Graphics g; 
     private NetworkStream stream; 
     public delegate void ConnectionCloseEventHandler(RemoteDesktopClient sender, EventArgs e); 
     public event ConnectionCloseEventHandler ConnectionClosed; 
     /// <summary> 
     /// Constructor (1 Overload) 
     /// </summary> 
     /// <param name="pixel_format">The bitmap's pixel format that will be used for every frame that is sent across the network.</param> 
     public RemoteDesktopClient(System.Drawing.Imaging.PixelFormat pixel_format) 
     { 
      format = pixel_format; 
     } 
     public void BeginConnection(int port, string host_ip) 
     { 
      IPAddress addr; 
      if (IPAddress.TryParse(host_ip, out addr)) 
      { 
       if (port > 0 && port < 65535) 
       { 
        client = new TcpClient(host_ip, port); 
        timer = new Timer(); 
        timer.Interval = Convert.ToInt32(Math.Pow(24, -1) * 1000); // 24 frames per second. 
        timer.Tick += new EventHandler(timer_Tick); 
        stream = client.GetStream(); 
        timer.Enabled = true; 

       } 
       else if (port > 0 && port > 65535) 
       { 
        throw new RemoteDesktopException(new ArgumentOutOfRangeException("port")); 
       } 
      } 
      else 
      { 
       throw new RemoteDesktopException("Error: Invalid IP address in string format. Make sure it is in the right format."); 
      } 
     } 

     void timer_Tick(object sender, EventArgs e) 
     { 
      bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); 

      g = Graphics.FromImage(bitmap); 
      g.CopyFromScreen(0, 0, 0, 0, bitmap.Size); 
      Cursors.Default.Draw(g, new Rectangle(Cursor.Position, Cursors.Default.Size)); 
      byte[] buffer = imageToByteArray(bitmap); 
      stream.Write(buffer, 0, buffer.Length); 

     } 
     public void EndConnection() 
     { 
      g.Dispose(); 
      stream.Close(); 
      stream.Dispose(); 
      bitmap.Dispose(); 
      timer.Enabled = false; 
      client.Close(); 
      ConnectionClosed(this, new EventArgs()); 
      return; 
     } 
     public Socket Socket 
     { 
      get 
      { 
       return client.Client; 
      } 
     } 
     byte[] imageToByteArray(System.Drawing.Image imageIn) 
     { 
      System.IO.MemoryStream ms = new System.IO.MemoryStream(); 
      imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif); 
      return ms.ToArray(); 
     } 
    } 
    /// <summary> 
    /// Represents all remote desktop runtime errors. Inherits from System.Exception. 
    /// </summary> 
    public class RemoteDesktopException : Exception 
    { 
     private string message; 
     private Exception ex; 
     /// <summary> 
     /// Constructor (+1 Overloads) 
     /// </summary> 
     /// <param name="error">The error message in string format.</param> 
     public RemoteDesktopException(string error) 
     { 
      message = error; 
     } 
     /// <summary> 
     /// Constructor (+1 Overloads) 
     /// </summary> 
     /// <param name="error">The error in System.Exception format.</param> 
     public RemoteDesktopException(Exception error) 
     { 
      ex = error; 
     } 
     public override string StackTrace 
     { 
      get 
      { 
       return base.StackTrace; 
      } 
     } 
     public override string HelpLink 
     { 
      get 
      { 
       return base.HelpLink; 
      } 
      set 
      { 
       base.HelpLink = value; 
      } 
     } 
     public override string Message 
     { 
      get 
      { 
       if (message != null) 
       { 
        return message; 
       } 
       else 
       { 
        return ex.Message; 
       } 
      } 
     } 
    } 
    public class DataEventArgs : EventArgs 
    { 
     private Image image; 
     public DataEventArgs(Image img) 
     { 
      image = img; 
     } 
     public System.Drawing.Image CurrentFrame 
     { 
      get 
      { 

       return image; 
      } 
     } 

    } 
} 

我加入這裏沖洗

void timer_Tick(object sender, EventArgs e) 
     { 
      bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); 

      g = Graphics.FromImage(bitmap); 
      g.CopyFromScreen(0, 0, 0, 0, bitmap.Size); 
      Cursors.Default.Draw(g, new Rectangle(Cursor.Position, Cursors.Default.Size)); 
      byte[] buffer = imageToByteArray(bitmap); 
      stream.Write(buffer, 0, buffer.Length); 
      stream.Flush(); 


     } 

是你指我放置stream.Flush()子程序的地方嗎? * 因爲它仍然不起作用。我也嘗試將NoDelay屬性設置爲true。 *

回答

4

Image.FromStream的速度不太可能是您的問題。您的代碼嘗試每秒發送24幀。假設您的屏幕設置爲1024 x 768,即786,432像素。 24位色,大約2.25兆字節。每秒24幀將是每秒54兆字節。

你的imageToByteArray方法創建一個GIF,它會壓縮一些。返回的字節數組有多大?也就是說,在你的timer_tick方法,您有:

byte[] buffer = imageToByteArray(bitmap); 
stream.Write(buffer, 0, buffer.Length); 

什麼是buffer.Length價值?

由於TCP開銷,千兆網絡會給你少一點100兆字節每秒的東西。我懷疑你在這裏遇到網絡限制。

通常,傳輸視頻的應用程序(實際上是在做什麼)可以進行差分壓縮。他們找出哪些像素髮生了變化,只發送這些像素。這大大降低了網絡帶寬。如果你真的想要24個FPS和任何尺寸的屏幕,你可能不得不這樣做。

1

你是不是在服務器端刷新流?嘗試在服務器代碼中調用Stream.Flush()。這聽起來像客戶端正在等待更多的數據來完成圖像,但它仍然在服務器流的緩衝區中。

+0

永不刷新流。我會嘗試。 – 2011-04-30 16:49:41

+0

感謝您的回答,但我很困惑在何處調用Flush方法。我只是不知道該把它放在哪裏。 – 2011-04-30 17:07:52

+0

這將不得不在服務器代碼中,它看起來不像你張貼。在將圖像寫入流之後的某個地方。 – 2011-04-30 17:11:21