簡體   English   中英

C#-使用StreamReader讀取HTTP請求

[英]C# - Reading HTTP requests with StreamReader

我正在用C#編寫一個TCP客戶端和一個服務器,它們使用手動編寫的HTTP請求相互通信。 我遇到的麻煩是使用StreamReaderNetwork Stream進行讀取。 到目前為止,我已經嘗試了許多方法,但無濟於事。

我從TCP客戶端收到的請求有多種形式。 對於更新數據庫,請求如下所示( CRLF是我用來表示"\\r\\n"字符串的常量):

HTTP 1.0:

“ POST /” +名稱+“ HTTP / 1.0” + CRLF +“ Content-Length:” +長度+ CRLF + CRLF +位置;

HTTP 1.1:

“ POST / HTTP / 1.1” + CRLF +主機名+“ Content-Length:” +長度+ CRLF + CRLF + nameLocString;

這些請求的格式正確,客戶端正在正確發送它們-我已經在我可以訪問的服務器上對該服務器進行了測試,可以對它們進行響應,而不會出現問題。

我的問題是我的TCP偵聽器代碼。 為了避免發布整個代碼,我將僅包含有問題的代碼部分(通過調試找出來)。

服務器代碼:

NetworkStream socketStream = new NetworkStream(connection);
StreamReader sr = new StreamReader(socketStream);

string input = ReadAllLinesWithNull(sr); // reading version 1
string input = ReadAllLinesWithEndOfStream(sr);  // reading version 2
string input = ReadAllLinesWithPeek(sr);  // reading version 3
string input = sr.ReadToEnd();  // reading version 4

使用的方法是:

static string ReadAllLinesWithNull(StreamReader sr)
{
    string input;
    string nextLine;
    input = sr.ReadLine();
    while ((nextLine = sr.ReadLine()) != null)
    {
        Console.WriteLine(input);
        input += nextLine;
    }
    sr.Close();
    return input;
}

static string ReadAllLinesWithEndOfStream(StreamReader sr)
{
    string input = "";
    while (!sr.EndOfStream)
    {
        input += sr.ReadLine();
    }
    sr.Close();
    return input;
}

static string ReadAllLinesWithPeek(StreamReader sr)
{
    string input = "";
    while (sr.Peek() >= 0)
    {
        input += sr.ReadLine();
    }
    sr.Close();
    return input;
}

這些閱讀方法均無效。 設置了我的連接超時后,我收到了IO異常消息,該消息讀取時間太長/強行關閉了連接。 我關閉了超時,“讀取”花費了不確定的時間。

多虧使用ReadLine()我能夠找出所有協議版本最終掛起的地方,並發現當存在兩個CRLF( "\\r\\n\\r\\n" )的簇時,流讀者無法對此進行處理並陷入困境。

您對如何解決這個問題有任何建議嗎? 我需要使用規范中包含多個CRLF的版本。

如果您需要任何其他信息,我將盡量提供合理的信息。

最后,我找到了解決問題的方法。 而不是使用

static string ReadAllLinesWithPeek(StreamReader sr)
{
    string input = "";
    while (sr.Peek() >= 0)
    {
        input += sr.ReadLine();
    }
    sr.Close();
    return input;
}

我不得不用

static string ReadAllLinesWithPeek(StreamReader sr)
{
    string input = "";
    while (sr.Peek() >= 0)
    {
        input += (char) sr.Read();
    }
    return input;
}

我仍然不確定為什么按行讀取輸入不起作用,但是一次按char讀取卻可以。

如果當前沒有可用數據,並且另一端尚未關閉該通道,則NetworkStream阻止進行Read操作。 TCP本身沒有消息的概念-該問題將在HTTP級別解決。

對於HTTP,您可以繼續讀取,直到您的數據包含\\r\\n\\r\\n序列為止為止,該序列將標​​頭與正文分開。 如何處理正文取決於存在的標頭:

  • Transfer-Encoding: chunked表示發件人將發送數據塊並將以長度為0的塊結尾
  • 不使用塊時應顯示Content-Length ,然后可以准確讀取那么多字節的數據
  • GET請求不應包含主體,如果未設置上述標頭,則可以假定此主體
  • Connection: close可用於響應,指示在發送所有響應數據后將關閉連接

如您所見, StreamReader.ReadLine()在解析標頭時會很好地工作,它也非常適合讀取塊,但不能用於讀取固定長度的正文。

我不知道從以前由StreamReader讀取的流中讀取數據(它可以將一些數據提前讀取到其緩沖區中)是多么可行,但是using圍繞它們的塊進行拍打只會導致底層流被關閉,除非您選擇一個構造函數重載

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM