通过C#套接字正确发送和接收? [英] Proper sending and receiving via C# sockets?

查看:118
本文介绍了通过C#套接字正确发送和接收?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用C#创建远程桌面服务器和客户端。服务器捕获屏幕,然后通过套接字将其发送到客户端。我正在使用下面的代码,虽然它只显示客户端上的jpeg图像的一部分。我认为这是因为图像是以多个数据包发送的,此时代码只读取一个数据包并显示它。任何人都可以解释我如何更改我的代码,以便在显示之前接收多个数据包(整个图像)。

I'm attempting to create a remote desktop server and client using C#. The server captures the screen and then sends it to the client via a socket. I'm using the code below although it only displays a part of the jpeg image on the client. I think this is because the image is sent in multiple packets and at the moment the code only reads the one packet and displays it. Can anyone explain how I would change my code so it receives multiple packets (the whole image) before displaying it.

服务器代码:

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.

As you can see, I'm using a timer which has the interval set to 30 for sending the image bytes.

客户代码:

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);
}

客户端用于接收图像,然后在表单的背景上显示。

The client is meant to receive the image and then display it on the form's background.

推荐答案

您需要在套接字通信中添加应用程序级协议。

You need to add application level protocol to your socket communications.

为发送的所有邮件添加标头。标头包含后面的字节数。它具有更简单的代码,并且具有字节数比使用终止序列更好的性能。

Add a header to all messages sent. The header contains the count of bytes that follow. It is simpler code and performs better to have a byte count than to kludge a termination sequence.

然后客户端执行两组读取:
1)读取已知在任何头中的字节数。

The client then does two sets of reads: 1) Read for the number of bytes that are known to be in any header.

2)从标题中提取字节数后,循环读取,直到得到指定的字节数。

2) After extracting the byte count from the header, loop reading until you get the indicated byte count.

所有正在编写套接字通信的人都必读的文章: http:// nitoprograms.blogspot.com/2009/04/message-framing.html
从那篇文章:重复这个咒语三次:TCP不对数据包进行操作.TCP对数据流进行操作。

A must-read article for all people who are writing socket communications: http://nitoprograms.blogspot.com/2009/04/message-framing.html From that article: Repeat this mantra three times: "TCP does not operate on packets of data. TCP operates on streams of data."

这篇关于通过C#套接字正确发送和接收?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆