代码在写入网络流时遇到问题

时间:2015-06-02 09:06:48

标签: c# network-programming windows-services

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

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

2 个答案:

答案 0 :(得分:0)

我不确定你是否应该有一个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();

答案 1 :(得分:0)

您开始从网络流(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);
}