代码在写入网络流时卡住

本文关键字:网络 代码 | 更新日期: 2023-09-27 17:52:12

我正在读取。bin文件并将其写入流。稍后,我将读取该流对象,然后将其写入网络流。代码如下:

public async Task<bool> UploadFirmware(Stream _stream)
        {                
            bool success = false;
            try
            {
                _tcpclient = new TcpClient();
                _tcpclient.Connect(_deviceip, port);
                _stream.Seek(0, SeekOrigin.Begin);
                m_NetworkStream = _tcpclient.GetStream();
                byte[] buffer = new byte[1024];
                m_ReadBuffer = new byte[1024];
                int readcount = 0;
                m_NetworkStream.BeginRead(m_ReadBuffer, 0, m_ReadBuffer.Length, new AsyncCallback(EndReceive), null);
                await Task.Run(() =>
                 {
                     while ((readcount = _stream.Read(buffer, 0, buffer.Length)) > 0)
                     {
                         m_NetworkStream.Write(buffer, 0, readcount);
                         m_NetworkStream.Flush();
                     }
                 });
                success = true;                              
            }
            catch (Exception ex)
            {}
            return success;
      }

正常情况下,这段代码工作正常,但有时在IP地址上,代码会卡在m_NetworkStream.Write(buffer, 0, readcount);上。问题是,我正在根据success值更新UI中的状态,但是代码在上面提到的行上被挂起并且根本没有出来。根本不会抛出异常来识别问题。因此,在UI中状态不会更新,并且会产生意想不到的结果。我无法确定问题所在。如有任何帮助,我将不胜感激。

编辑:

同样,我必须并行地执行一个操作。EndReceive的代码如下:

private void EndReceive(IAsyncResult ar)
        {
            try
            {
                int nBytes;
                nBytes = m_NetworkStream.EndRead(ar);
                if (nBytes > 0)
                {
                    string res = Encoding.UTF8.GetString(m_ReadBuffer, 0, nBytes);
                    DeviceStatus status = new DeviceStatus();
                    string[] readlines = res.Split(new string[] { CRLF }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string readline in readlines)
                    {
                        if (readline.StartsWith("CODE"))
                        {
                            status.code = Convert.ToInt32(readline.Replace("CODE=", ""));
                            break;
                        }
                    }
                    status.deviceip = this._deviceip;
                    status.port = this.port;
                    status.DeviceID = this._DeviceID;
                    status.FirmwareID = this._FirmwareID;
                    status.FilePath = this._Path;
                    StatusUpdate(status);
                    m_ReadBuffer = new byte[1024];
                }

            }
            catch (ObjectDisposedException ods)
            {
                return;
            }
           if (_tcpclient.Connected)
                m_NetworkStream.BeginRead(m_ReadBuffer, 0, m_ReadBuffer.Length, new AsyncCallback(EndReceive), null);
        }

代码在写入网络流时卡住

我不确定你是否应该有一个while循环,以便将从文件(从磁盘)读取的字节写入网络流…你可以读取所有字节,写入流,并在一次操作中刷新。

你还可以添加一个写超时来指定在流写操作失败之前可以通过多少时间,以防止任何"挂起"的可能性。

经过这些修改,代码看起来像这样:
 // make the tcp connection to the remote endpoint
 _tcpclient = new TcpClient();
 _tcpclient.Connect(_deviceip, port);
 // read the file bytes in one operation
 var allBytes = File.ReadAllBytes(fileNameOnDisk);
 // get the network stream
 m_NetworkStream = _tcpclient.GetStream();
 // wait a max of 500ms for the write operation to happen
 m_NetworkStream.WriteTimeout = 500;
 // write the file bytes to the stream and flush without while/stream/seek etc.
 m_NetworkStream.Write(allBytes, 0, allBytes.Length);
 m_NetworkStream.Flush();

当你完成流时:

 m_NetworkStream.Close();
 m_NetworkStream.Dispose();

看起来很奇怪,您开始从网络流(m_NetworkStream.BeginRead(...))中读取,并立即在另一个线程中开始写入相同的流(m_NetworkStream.Write(...))。我建议先读完书再开始写作。你也可以使用Stream.CopyTo在流之间复制数据。

public async Task<bool> UploadFirmware(Stream fileStream, IPEndPoint deviceEP)
{
    bool success = false;
    try
    {
        TcpClient client = new TcpClient();
        client.Connect(deviceEP);
        NetworkStream networkStream = client.GetStream();
        BeginReadFromDevice(networkStream);
        // send bin data to device
        await fileStream.CopyToAsync(networkStream);
        success = true;
    }
    catch (Exception)
    {
    }
    return success;
}
private void BeginReadFromDevice(Stream networkStream)
{
    byte[] buffer = new byte[1024];
    networkStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(EndReceive), null);
}