【问题标题】:async / await TCP listener saving images from cameras异步 / 等待 TCP 侦听器从相机保存图像
【发布时间】:2019-04-11 20:42:16
【问题描述】:

大家好,我有一个大问题:我创建了一个 Windows 窗体,它作为服务器侦听连接到同一专用网络的某些摄像机发送的 TCP 消息。 当摄像头检测到某些东西时,每个摄像头都会向服务器发送一条 tcp 消息,服务器必须在不冻结 gui 界面的情况下连续工作,并且必须处理每条 TCP 消息。该数据的处理包括保存发送方相机拍摄的图像。服务器将这些图像保存到一个文件夹中,这是我的问题: 服务器无法正确保存每个图像:看起来在传输过程中丢失了一些字节,但我认为所有字节都丰富了服务器,发生了更深层次的事情。也许这可能是我编写异步/等待服务器的方式?

我有一个 TcpListener 列表,因为我必须使用更多服务器,每个选项卡一个。

保存的图像如下所示 https://imgur.com/xtlgHPk https://imgur.com/CcvWbDH

如您所见,没有完全保存,除了出于某种未知原因的人 https://imgur.com/G25UPSS

    public void TcpServer(int port)
    {
        IPAddress ipAddress = null;
        string hostName = Dns.GetHostName();
        IPHostEntry ipHostInfo = Dns.GetHostEntry(hostName);
        for (int i = 0; i < ipHostInfo.AddressList.Length; ++i)
        {
            if (ipHostInfo.AddressList[i].AddressFamily ==
              AddressFamily.InterNetwork)
            {
                ipAddress = ipHostInfo.AddressList[i];
                _listener.Add( new TcpListener(ipAddress, port));
                ReceiveDataAsync();
                break;
            }
        }
        if (ipAddress == null)
            throw new Exception("No IPv4 address for server");

    }

    private async void ReceiveDataAsync()
    {
        try
        {
            _listener[tbServer.SelectedIndex].Start();
            while (true)
            {
                var tcpClient = await _listener[tbServer.SelectedIndex].AcceptTcpClientAsync();
                ReadDataFromClientAsync(tcpClient);
            }
        }
        catch (Exception e)
        {
            MessageBox.Show("Errore: ", e.Message.ToString());
        }
    }

    private async Task ReadDataFromClientAsync(TcpClient client)
    {
        try
        {
            using (NetworkStream stream=client.GetStream())
            {
                int selectedTabIndex, indexOfPort;
                string endPoint;
                while (client.Connected)
                {
                    int count = 0;
                    var countBytes = new byte[4];
                    for (int i = 0; i < 6; i++)
                    {
                        count = await stream.ReadAsync(countBytes, 0, countBytes.Length);
                    }
                    //The data dimension of the TCP message is into his header, 24th byte.
                    if (count == 0)
                    {
                        break;
                    }

                    byte[] bytes = new byte[BitConverter.ToUInt32(countBytes, 0)];
                    await stream.ReadAsync(bytes, 0, bytes.Length);


                    indexOfPort = Settings.getIndexOfPort(client.Client.LocalEndPoint.ToString());
                    endPoint = client.Client.RemoteEndPoint.ToString();
                    selectedTabIndex = Settings.getIndexOfPort(client.Client.LocalEndPoint.ToString());
                    updateGui("entry", indexOfPort,endPoint);

                    BufferData bufferService = new BufferData();
                    CameraMessage cameraMessage = await bufferService.writeBufferData(bytes.ToList());
                    if (cameraMessage == null)
                        return;

                  //doing some stuff

                        msgToShow = await bufferService.SaveImageFromCamera(cameraMessage);
                      //doing other stuff  

                    }
                    client.Close();
                    closeCommunication(selectedTabIndex,indexOfPort,endPoint);
                }
            }
        }
        catch (IOException e)
        {
            updateGui("stop");
        }

    }

BufferData 类:

             public class BufferData
            {
              public async Task<CameraMessage> writeBufferData(List<byte> bytesList)
          {
        CameraMessage cameraMessage = new CameraMessage();

        try
        {
            int num = 0;
            int startSubData = 0;
            for (int startData = 0; startData < bytesList.Count-8; startData = startSubData + num)
            {

                int codeDataMessage = BitConverter.ToInt32(bytesList.GetRange(startData, 4).ToArray(), 0);
                int indexDataSize = startData + 4;
                int SizeDataMessage = BitConverter.ToInt32(bytesList.GetRange(indexDataSize, 4).ToArray(), 0);
                startSubData = indexDataSize + 4;
                byte[] array = bytesList.GetRange(startSubData, SizeDataMessage).ToArray();
                num = 0;
                switch (codeDataMessage)
                {
                    case 14020:
                        cameraMessage.image = await this.Base64ToImage(array);
                        num = this.OffSetStringType(SizeDataMessage);
                        break;
                }
            }
            return cameraMessage;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message.ToString());
            return null;
        }
    }

    public async Task<string> SaveImageFromCamera( CameraMessage cameraMessage)
    {
        string path = Settings.pathFolder + cameraMessage.ld_I_SN + @"\Images\";
        string res;
        if (!Directory.Exists(Settings.pathFolder+cameraMessage.ld_I_SN))
        {
            Directory.CreateDirectory(Settings.pathFolder + cameraMessage.ld_I_SN + @"\Images");
        }
            try
            {
            await Task.Run(() => { cameraMessage.image.Save(path + cameraMessage.ld_I_FILENAME, ImageFormat.Jpeg); });
                res = "#3 - OK - IMMAGINE SALVATA CON SUCCESSO";
                 cameraMessage.image.Dispose();
            return res;

        }
        catch (Exception ex)
            {
                res = "#3 - ERR - IMMAGINE NON SALVATA";
            return res;

        }


    }


    public async static Task<Image> Base64ToImage(byte[] imageBytes)
    {
        MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
        ms.Write(imageBytes, 0, imageBytes.Length);
        return System.Drawing.Image.FromStream(ms, true);
    }


}

【问题讨论】:

  • 所以你正在向服务器发送图像的字节数,所以它知道它可以读取多少字节。问题2,你为什么要把它转换成base64?。这也与 asyc 和 await 似乎无关
  • 为什么你读取了前 24 个字节但只保留了 20-24,然后用最后 4 个字节调用BitConverter.ToUInt32(countBytes, 0)?
  • 看起来您正在向每个包含字节数的图像发送一个四字节的标头。这四个字节不会被放入 cameraMessage。但是在消息处理中你跳过了错误的四个字节。
  • 谢谢大家的回答。我正在关注具有此 TCP 标头 ibb.co/c8tJ3fD 如您所见,从 20 到 24 的字节用于数据消息的大小,因此我将其转换为字节以创建缓冲区以读取消息。在数据消息中传输的每个字段都遵循此架构ibb.co/d4L4D75

标签: c# image asynchronous tcp async-await


【解决方案1】:

您的核心问题是您假设套接字读取将读取您要求它读取的所有字节。这不是套接字读取的工作方式。

当您调用await stream.ReadAsync(bytes, 0, bytes.Length) 时,流将读取从1 到bytes.Length 的任意数量的字节。它将返回实际读取的字节数。只要您的缓冲区尚未完全读取,您就需要考虑到这一点并再次读取。

请注意,对于标头字节和有效负载字节都必须这样做。

【讨论】:

  • 感谢您的帮助...我该怎么做?我明白你在说什么,我认为问题可能是这样的,但我不知道如何告诉 c# 读取直到实际读取了 buffer.length 个字节
  • 流读取操作返回已读取的字节数。因此,请继续阅读,直到您读取了整个缓冲区长度,每次根据已读取的字节数调整您的偏移量和请求的读取长度。
猜你喜欢
  • 2015-11-06
  • 1970-01-01
  • 2018-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-16
  • 2014-04-08
  • 2018-12-02
相关资源
最近更新 更多