簡體   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