2011-04-30 85 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