通过套接字发送和接收图像 [英] Sending and receiving images via a socket

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

问题描述

我有一个C#桌面应用程序.它连接到我网络上的另一台UWP C#应用程序.

I have a C# desktop app. It connects to another PC on my network which is a UWP C# app.

我正在尝试将一个图像或2个图像发送到侦听套接字,并进行测试,以使我获得侦听套接字将图像发送回给我.

I am trying to send an image or 2 to my listening socket and to test this I get the listening socket to send me the image back.

问题在于,即使我的服务器收到了所有原来发送给客户端的图像,也没有相同的大小.

The trouble is that even though my server recieves all the bytes that were orginally sent the recieved image back to the client is not of the same size.

有时候,返回的字节是正确的,我得到了整个图像,而当我尝试发送2张图像时,第一个就可以了,而第二个就不可以了.

To make this even more weird is sometimes the returned bytes are correct and I get the whole image and when I attempt to send 2 images the 1st one is OK and the 2nd one is not.

然后它将/可以恢复为没有正确发送回的图像.

Then it will/can revert back to no images being sent back correctly.

我认为可能与异步/等待部分有关,我不确定如何处理.

I think is maybe to do with the async/await parts bit I am not sure how.

这是我的服务器代码:

using (IInputStream input = args.Socket.InputStream)
{
    byte[] data = new byte[BufferSize];
    IBuffer buffer = data.AsBuffer();
    uint dataRead = BufferSize;
    while (dataRead == BufferSize)
    {
        await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);
        requestInBytes.AddRange(data.Take((int) buffer.Length));
        dataRead = buffer.Length;
    }
}
var ct = requestInBytes.Count;

然后我跳出标题信息:

int counter = 0;
counter = requestCommand[0].Length;
counter = counter + requestCommand[1].Length;
counter = counter + requestCommand[2].Length;
counter = counter + requestCommand[3].Length;
counter = counter + requestCommand[4].Length;
counter = counter + requestCommand[5].Length;
counter = counter + 6;

现在我提取图像:

var imgBody = new byte[totalBytes.Length- counter];
System.Buffer.BlockCopy(totalBytes, counter, imgBody, 0, imgBody.Length);
byteArray = imgBody;

然后仅将图像发送回去:

And send just the image back:

using (IOutputStream output = args.Socket.OutputStream)
{
    using (Stream response = output.AsStreamForWrite())
    {
        MemoryStream stream = new MemoryStream(byteArray);
        await response.WriteAsync(byteArray, 0, byteArray.Length);
        await response.FlushAsync();
    }
}

这是我的客户代码:

StringBuilder sb = new StringBuilder();
foreach (var gallery in Shared.CurrentJobGallery)
{
    try
    {
        sb.Clear();
        sb.Append(GeneralTags.ACTION_ADD);
        sb.Append(Shared.DLE);
        sb.Append("GALLERY");
        sb.Append(Shared.DLE);
        sb.Append(Shared.CurrentClientId);
        sb.Append(Shared.DLE);
        sb.Append(gallery.Title);
        sb.Append(Shared.DLE);
        sb.Append(gallery.Description);
        sb.Append(Shared.DLE);
        sb.Append(jobRef);
        sb.Append(Shared.DLE);
        byte[] galleryHdr = Encoding.UTF8.GetBytes(sb.ToString());
        byte[] byteArray = new byte[galleryHdr.Length + gallery.ImageData.Length];

        Buffer.BlockCopy(galleryHdr, 0, byteArray, 0, galleryHdr.Length);
        Buffer.BlockCopy(gallery.ImageData, 0, byteArray, galleryHdr.Length, gallery.ImageData.Length);
        List<byte> requestInBytes2 = new List<byte>();
        System.Diagnostics.Debug.WriteLine("SENT: " + gallery.ImageData.Length.ToString());
        using (TcpClient clientSocket = new TcpClient())
        {
            await clientSocket.ConnectAsync(GeneralTags.RASPBERRY_PI_IP_ADDRESS, GeneralTags.RASPBERRY_PI_PORT);
            using (NetworkStream serverStream = clientSocket.GetStream())
            {
                List<byte> requestInBytes = new List<byte>();

                serverStream.Write(byteArray, 0, byteArray.Length);
                serverStream.Flush();
                int i;
                Byte[] bytes = new Byte[1024];
                do
                {
                    i = serverStream.Read(bytes, 0, bytes.Length);
                    byte[] receivedBuffer = new byte[i];
                    Array.Copy(bytes, receivedBuffer, i);

                    requestInBytes2.AddRange(receivedBuffer);
                } while (serverStream.DataAvailable);

            }
        }

        using (MemoryStream ms = new MemoryStream())
        {
            System.Diagnostics.Debug.WriteLine("BACK: " + requestInBytes2.Count.ToString());
            ms.Write(requestInBytes2.ToArray(), 0, requestInBytes2.ToArray().Length);
            Shared.ViewImage(Image.FromStream(ms, true));
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.ToString());
    }
}

推荐答案

您的问题是TCP套接字基于,而不是数据包.的确,在线"所有内容都是一个数据包,但是当您使用TCP时,您无法控制如何将数据拆分为数据包或将其重组为流.

Your problem is that TCP sockets are based around streams, not packets. It's true that "on the wire" everything is a packet, but when you're using TCP, you have no control over how the data is split up into packets or is reassembled into a stream.

尤其是,这行代码不正确:

In particular, this line of code is incorrect:

await input.ReadAsync(buffer, BufferSize, InputStreamOptions.Partial);

根据文档 ,则必须使用从ReadAsync返回的缓冲区.另外请注意,此缓冲区可能是部分图像,并且要由您的代码来检测这种情况,如有必要,请阅读更多内容并将这些块附加在一起.另外,缓冲区可能包含一个图像的一部分和下一个图像的一部分;还要由您的代码来检测并正确处理.

According to the docs, you must use the buffer returned from ReadAsync. Also note that this buffer may be a partial image, and it's up to your code to detect that situation, read more if necessary, and append those blocks together. Also, the buffer may contain part of one image and part of the next image; it's also up to your code to detect that and handle it correctly.

因此,大多数TCP应用程序都使用某种形式的消息框架(在我的博客中有更详细的描述).请注意,做到这一点非常困难.

For this reason, most TCP applications use some form of message framing (described in more detail on my blog). Note that getting this right is surprisingly hard.

我强烈建议您使用SignalR而不是原始TCP套接字. SignalR为您处理消息帧,并且具有自我托管功能(即不需要ASP.NET).

I strongly recommend that you use SignalR instead of raw TCP sockets. SignalR handles message framing for you, and it is capable of self-hosting (i.e., it does not require ASP.NET).

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

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