繁体   English   中英

StreamReader完成后从NetworkStream读取失败

[英]Reading from a NetworkStream fails after StreamReader did

我有一种方法可以以非常原始的方式从Stream(实际上是NetworkStream)读取HTTP请求。 首先,我逐行阅读标题,当我看到分隔符(又名空行)时,我开始阅读正文。

代码如下:

public byte[] ReceiveHttp(Stream stream)
{
    var headerLines = new List<string>();
    using (var reader = new StreamReader(stream, Encoding.ASCII, false, 8192, true))
    {
        var requestLine = reader.ReadLine();
        while (true)
        {
            var headerLine = reader.ReadLine();
            if (string.IsNullOrEmpty(headerLine))
            {
                // all header lines read
                break;
            }
            headerLine = headerLine.Trim();
            headerLines.Add(headerLine);
        }
    }

    var contentLength = RetrieveContentLengthFromHeaderLines(headerLines);

    var bytes = new byte[contentLength];
    var readbytesCount = 0;

    while (readbytesCount < contentLength)
    {
        var chunkBytesCount = stream.Read(bytes, 0, contentLength);
        readbytesCount += chunkBytesCount;
    }

    return bytes;
}

现在我的问题是,身体的后续读取有时会挂起。 我的意思是要调用stream.Read块,直到达到某种超时。

当用某些自定义代码替换所有StreamReader.ReadLine() (实际上是从代码中删除StreamReader ,该代码逐字节读取一行,直到发生换行符为止,该问题永远不会发生。

因此,我想StreamReader中有某种缓冲/缓存,它可能已经读取了整个消息,但对后续的流操作隐藏了该消息。 但这只是一个猜测。

有人有一个主意吗,是什么导致了这种现象,以及如何在不使用自定义逐字节ReadLine方法的情况下解决该问题?

我已经评论过,使用StreamReader读取http协议的标头非常复杂(无法读取)。 您必须直接阅读Stream并“手动”拆分。

我的分线器:

// If you want to use UTF8:
// var encoding = (Encoding)Encoding.UTF8.Clone();
var encoding = Encoding.GetEncoding("iso-8859-1"); 
var decoder = encoding.GetDecoder();

//Encoding.ASCII
var headerLines = new List<string>();

var sb = new StringBuilder();
byte[] bytes = new byte[1];
char[] chars = new char[2];

while (true)
{
    int curr = stream.ReadByte();
    char ch = '\0';

    bool newLine = false;

    if (curr == -1)
    {
        newLine = true;
    }
    else
    {
        bytes[0] = (byte)curr;

        // There is the possibility of a partial invalid 
        // character (first byte of UTF8) plus a new valid 
        // character. In this case decoder.GetChars will
        // return 2 chars
        int count = decoder.GetChars(bytes, 0, 1, chars, 0);

        for (int i = 0; i < count; i++)
        {
            ch = chars[i];

            if (ch == '\n')
            {
                newLine = true;
            }
            else
            {
                sb.Append(ch);
            }
        }
    }

    if (newLine)
    {
        string str = sb.ToString();

        // Handling of \r\n
        if (ch == '\n' && str[str.Length - 1] == '\r')
        {
            str = str.Remove(str.Length - 1);
        }

        str = str.Trim();

        if (str.Length != 0)
        {
            headerLines.Add(str);
            sb.Clear();
        }
        else
        {
            break;
        }
    }

    if (curr == -1)
    {
        break;
    }
}

请注意,对于标题,建议的编码为ISO-8859-1。 行尾可以是\\r\\n\\n 代码非常复杂,因为我想处理UTF8。 对于其他编码,它应该没有用。 请注意,在进行长度检查之前 ,我会使用Trim() ,因此仅充满空格的行仍将停止读取标头。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM