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

스트림을 플러시하지 않았습니다. 나는 그것을 시도 할 것이다. –

+0

답변 주셔서 감사 합니다만, Flush 메서드를 호출 할 곳은 혼란 스럽습니다. 나는 어디에 넣어야할지 모른다. –

+0

게시 된 것처럼 보이지 않는 서버 코드에 있어야합니다. 이미지를 스트림에 쓴 직후의 어딘가에. –

관련 문제