通过套接字发送和接收图像

时间:2015-11-21 13:00:58

标签: c# sockets uwp raspberry-pi2 iot

我有一个C#桌面应用。它连接到我的网络上的另一台PC,这是一个UWP C#app。

我正在尝试将图像或2发送到我的侦听套接字并对其进行测试,我得到了侦听套接字以便将图像发回给我。

问题在于,即使我的服务器收到了所有已发送的字节,但收到的图像也不会返回给客户端。

为了使这更奇怪有时返回的字节是正确的,我得到整个图像,当我尝试发送2个图像时,第一个是OK,第二个没有。

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

我认为可能与async / await部分位有关,我不知道如何。

这是我的服务器代码:

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;

然后发回图像:

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

1 个答案:

答案 0 :(得分:3)

您的问题是TCP套接字基于,而不是数据包。电线&#34;电线&#34;是真的。一切都是数据包,但是当你使用TCP时,你无法控制数据如何被分成数据包或被重新组装成流。

特别是,这行代码不正确:

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

根据the docs,您必须使用从ReadAsync返回的缓冲区。另请注意,此缓冲区可能是部分映像,它可以您的代码来检测该情况,必要时可以阅读更多内容并将这些块附加在一起。此外,缓冲区可能包含一个图像的一部分和下一个图像的一部分;它还可以通过您的代码来检测并正确处理它。

出于这个原因,大多数TCP应用程序使用某种形式的message framing(在我的博客上有更详细的描述)。请注意,实现这一目标非常困难。

我强烈建议您使用SignalR而不是原始TCP套接字。 SignalR为您处理消息框架,它能够自托管(即,它不需要ASP.NET)。