0

C#を使用してリモートデスクトップサーバーとクライアントを作成しようとしています。サーバーは画面をキャプチャし、ソケットを介してクライアントに送信します。クライアントにjpeg画像の一部しか表示されませんが、以下のコードを使用しています。これは、画像が複数のパケットで送信され、現時点ではコードが1つのパケットのみを読み取って表示するためだと思います。コードを表示する前に複数のパケット(画像全体)を受信するようにコードを変更する方法を誰かが説明できますか?

サーバーコード:

Socket serverSocket;
Socket clientSocket;

public Form1()
{
    InitializeComponent();

    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        serverSocket = new Socket(AddressFamily.InterNetwork,
                                  SocketType.Stream,
                                  ProtocolType.Tcp);

        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8221);

        serverSocket.Bind(ipEndPoint);
        serverSocket.Listen(4);

        //Accept the incoming clients
        serverSocket.BeginAccept(new AsyncCallback(OnAccept), null);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Stream Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private void timer1_Tick(object sender, EventArgs e)
{
    timer1.Stop();

    Rectangle bounds = new Rectangle(0, 0, 1280, 720);
    Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);

    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }

    System.IO.MemoryStream stream = new System.IO.MemoryStream();

    ImageCodecInfo myImageCodecInfo;
    System.Drawing.Imaging.Encoder myEncoder;
    EncoderParameter myEncoderParameter;
    EncoderParameters myEncoderParameters;

    myEncoderParameters = new EncoderParameters(1);

    myImageCodecInfo = GetEncoderInfo("image/jpeg");
    myEncoder = System.Drawing.Imaging.Encoder.Quality;
    myEncoderParameter = new EncoderParameter(myEncoder, 40L);
    myEncoderParameters.Param[0] = myEncoderParameter;

    bitmap.Save(stream, myImageCodecInfo, myEncoderParameters);

    byte[] imageBytes = stream.ToArray();

    stream.Dispose();

    clientSocket.Send(imageBytes);

    timer1.Start();
}

ご覧のとおり、画像バイトを送信するために間隔が30に設定されているタイマーを使用しています。

クライアントコード:

public Socket clientSocket;

byte[] byteData = new byte[2048];
MemoryStream ms;

public Form1()
{
    InitializeComponent();

    backgroundWorker1.RunWorkerAsync();

    this.DoubleBuffered = true;
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
        clientSocket = new Socket(AddressFamily.InterNetwork,
                       SocketType.Stream, ProtocolType.Tcp);

        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("MY EXTERNAL IP HERE"), 8221);

        //Connect to the server
        clientSocket.BeginConnect(ipEndPoint,
            new AsyncCallback(OnConnect), null);

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "SGSclient",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
    }
}

private void OnConnect(IAsyncResult ar)
{
    try
    {
        //Start listening to the data asynchronously
        clientSocket.BeginReceive(byteData,
                                   0,
                                   byteData.Length,
                                   SocketFlags.None,
                                   new AsyncCallback(OnReceive),
                                   null);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "Stream Error",
            MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

private void OnReceive(IAsyncResult ar)
{
    try
    {
        int byteCount = clientSocket.EndReceive(ar);

        ms = new MemoryStream(byteData);

        using (BinaryReader br = new BinaryReader(ms))
        {
            this.BackgroundImage = Image.FromStream(ms).GetThumbnailImage(this.ClientRectangle.Width, this.ClientRectangle.Height, null, IntPtr.Zero);
        }

    }
    catch (ArgumentException e)
    {
        //MessageBox.Show(e.Message);
    }

    clientSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), null);
}

クライアントは、画像を受信して​​フォームの背景に表示することを目的としています。

4

3 に答える 3

4

ソケット通信にアプリケーションレベルのプロトコルを追加する必要があります。

送信されるすべてのメッセージにヘッダーを追加します。ヘッダーには、後続のバイト数が含まれます。これはコードが単純であり、終了シーケンスを混乱させるよりもバイトカウントを使用する方がパフォーマンスが優れています。

次に、クライアントは2セットの読み取りを実行します。1)任意のヘッダーにあることがわかっているバイト数を読み取ります。

2)ヘッダーからバイト数を抽出した後、指定されたバイト数が得られるまで読み取りをループします。

ソケット通信を書いているすべての人にとって必読の記事:http://nitoprograms.blogspot.com/2009/04/message-framing.html その記事から:このマントラを3回繰り返します:「TCPはパケットで動作しませんTCPはデータのストリームで動作します。」

于 2012-08-03T20:05:59.760 に答える
1

私は以前に同様の質問に答え、あなたがやろうとしていることを正確に実行すると思う完全に機能する例を提供しました。参照:TCP接続を介したスクリーンショットの転送

于 2012-08-03T19:46:14.210 に答える
0

イメージの最後に区切り文字を設定する必要があります。これは、イメージが終了したことをサーバーに通知するバイトのセットです。これは、ファイルの終わり(EOF)またはメッセージの終わりとも呼ばれます。TCPは画像をアプリの論理パケットに分割しないため、独自の情報制御を作成する必要があります。

ロジックは次のようになります: CLIENT

byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ImageBytes = GetImageBytes();
byte[] BytesToSend = new byte[EndOfMessage.Length + ImageBytes.Length];
Array.Copy(ImageBytes, 0, BytesToSend);
Array.Copy(EndOfMessage, 0, BytesToSend, ImageBytes.Length, EndOfMessage.Length);

SendToServer(BytesToSend);

サーバ

byte[] EndOfMessage = System.Text.Encoding.ASCII.GetBytes("image_end");
byte[] ReceivedBytes;

while(!IsEndOfMessage(ReceivedBytes, EndOfMessage ))
{
//continue reading from socket and adding to ReceivedBytes
}

ReceivedBytes = RemoveEndOfMessage(ReceivedBytes, EndOfMessage );
PrintImage(ReceivedBytes);

私は現在仕事をしていますが、完全な例を提供することはできません。申し訳ありません。

よろしく


サポート方法:

private bool IsEndOfMessage(byte[] MessageToCheck, byte[] EndOfMessage)
{
    for(int i = 0; i++; i < EndOfMessage.Length)
    {
        if(MessageToCheck[MessageToCheck.Length - (EndOfMessage.Length + i)] != EndOfMessage[i])
            return false;
    }

    return true;
}

private byte[] RemoveEndOfMessage(byte[] MessageToClear, byte[] EndOfMessage)
{
    byte[] Return = new byte[MessageToClear.Length - EndOfMessage.Length];
    Array.Copy(MessageToClear, Return, Return.Length);

    return Return;
}

繰り返しになりますが、私はそれらをテストできなかったので、いくつかのバグを見つけるかもしれません。

于 2012-08-03T19:06:52.183 に答える