异步/等待TCP侦听器从摄像机保存图像

时间:2019-04-11 20:42:16

标签: c# image asynchronous tcp async-await

大家好,我有一个大问题:我创建了一个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);
    }


}

1 个答案:

答案 0 :(得分:0)

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

调用await stream.ReadAsync(bytes, 0, bytes.Length)时,流将从1bytes.Length读取任意数量的字节。它将返回实际读取的字节数。只要没有完全读取缓冲区,就需要考虑并重新读取。

请注意,必须同时对标头字节有效负载字节进行此操作。