【问题标题】:Receiving data in C# through a data Stream and reading data through boost:asio http server example在 C# 中通过数据流接收数据并通过 boost:asio http 服务器示例读取数据
【发布时间】:2015-02-14 02:16:36
【问题描述】:

所以我的问题是我有一个文件想发布到我的boost:asio http 服务器。客户端应用程序使用 C#。所以我尝试根据这里的很多帖子甚至微软自己的网站做以下事情。

string fileToSendServer = "Contains lots of data that needs to be written to file";
byte[] byteArray = UTF8Encoding.UTF8.GetBytes(fileToSendServer);

// Create a request using a URL that can receive a post. 
request = WebRequest.Create(destination);

// Set the Method property of the request to POST.
request.Method = "POST";
// Set the ContentType property of the WebRequest.
request.ContentType = "application/octet-stream";

// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
using (dataStream = request.GetRequestStream())
{
    // Write the data to the request stream.
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Flush();
    // Close the Stream object.
    dataStream.Close();
}

客户端一直到达GetRequestStream(),这似乎将标头发送到等待服务器。服务器处理标头并且从不接收来自Write() 的字节。

我尝试使用 Fiddler2 来查看数据包,但我的 IT 已锁定我的机器,因此我无法运行 Fiddler。

当我单步执行客户端代码时,所有代码行都会执行。当我在服务器上单步执行时,只能在流中找到标头。

需要发送的数据是由客户端生成的,而不是真正的文件,直到它应该被写入服务器端的文件。该服务器类似于boost::asio http 示例服务器之一。所以我不知道它是客户端还是服务器。我已经通过了解析传入输入的代码,并且从未收到过数据。所以我查看了连接,据我所知,传入数据没有阻塞。

编辑: 好的,根据答案(包括我自己的),我取得了一些重大进展。一半的问题是 c# 在发送之前没有读取所有内容。现在 C# 客户端正在读取和发送数据。客户端报告发送命令发送了所有字节。但是boost:asio http server 3 仍然没有收到所有数据。问题是我正在使用示例 http 服务器,而 request module 似乎并未捕获所有数据。它一次读取一个字节,并且似乎在 0x1f48 字节的内容处死掉。

template <typename InputIterator>
boost::tuple<boost::tribool, InputIterator> parse(request& req,
    InputIterator begin, InputIterator end)
{
    while (begin != end)
    {
        boost::tribool result = consume(req, *begin++);
        if (result || !result)
        {
            return boost::make_tuple(result, begin);
        }
    }
    boost::tribool result = boost::indeterminate;
    if(state_ == getting_content) {
        result = boost::indeterminate;
    }
    return boost::make_tuple(result, begin);
}

仅从请求中读取 8008 个字节时开始 == 结束。

【问题讨论】:

  • 如果没有看到基于 Asio 的服务器代码,恐怕很难猜出问题所在。
  • 那是很多代码。这是来自 boost asio 的 http server 3 示例。该示例看起来是正确的,只是他们使用的 read_some 函数将在任意数量的字节后停止接收。它不会等待我发送帖子的有效负载/内容。这似乎确实是 Web 请求的问题,因为它似乎是在发送写入之前的标头。

标签: c# c++ stream boost-asio webrequest


【解决方案1】:

(此答案基于您在当前接受的答案中提供的新信息)

所有实现Read 的Stream 类只需要读取最多传入的字节数以进行计数。这就是它返回 int 的全部原因。

另外,由于Read 的参数不采用long,如果返回的内容大于Int32.MaxLength,您仍然会丢失数据。

正确的做法是读入较小的缓冲区,然后将该缓冲区复制到较大的数组中。

byte[] data = new byte[response.ContentLength];
byte[] buffer = new byte[4 << 10]; //4k buffer, you can tweak it if you need to
long offset = 0;
int read;
do
{
    read = dataStream.Read(buffer, 0, buffer.Length);
    Array.Copy(buffer, 0, data, offset, read);
    offset += read;
} while (read > 0);

我不知道List&lt;byte&gt; content 是做什么用的,如果您只是要将data 移动到content 请注意,如果response.ContentLength 大于Int32.MaxLength,您可能会遇到一些问题,因为没有成员可以使用索引拉出或通过long 而不是int 获取长度。

【讨论】:

    【解决方案2】:

    显然response.GetResponseStream() 返回一个Stream,而不是Read() 整个响应。为了解决这个问题,我必须在响应中建立以下内容:

    byte[] data = new byte[response.ContentLength];
    int offset = 0;
    while (offset < response.ContentLength)
    {
        offset += dataStream.Read(data, offset, (int)(response.ContentLength - offset));
    }
    List<byte> content = new List<byte>(2 * (int)response.ContentLength);
    

    然后,我能够通过第二个流写出,它最终确实接收到了所有发送的内容。每次我在此更改之前检查文件输出时,该文件都包含确切的内容。因此,似乎整个问题是基于初始响应而不是“读取”所有发送的数据。

    编辑:

    此外,进入服务器的数据不完整。 boost:asio http 示例代码在捕获所有内容数据方面存在问题。我只会收到一部分传入的内容或文件数据。它似乎每次都停在 8008 字节。我发现解析函数不正确。所以我修改成这样:

            template <typename InputIterator>
            boost::tuple<boost::tribool, InputIterator> parse(request& req,
                InputIterator begin, InputIterator end)
            {
                //may have to handle multipart here.
                while (begin != end)
                {
                    boost::tribool result = consume(req, *begin++);
                    if (result || !result)
                    {
                        return boost::make_tuple(result, begin);
                    }
                }
                boost::tribool result = boost::indeterminate;
                if(state_ == getting_content) {
                    if(req.content.length() < content_length_) {
                        result = boost::indeterminate;
                    } else {
                        result = true;//boost::indeterminate;
                    }
                }
                return boost::make_tuple(result, begin);
            }
    

    最重要的部分是检查content 的长度并为这个函数返回indeterminate。然后确保connection 有更多read_some 的代码,示例代码确实有。

    【讨论】:

      猜你喜欢
      • 2018-08-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-25
      • 1970-01-01
      相关资源
      最近更新 更多