[英]C# - Reading HTTP requests with StreamReader
我正在用C#編寫一個TCP客戶端和一個服務器,它們使用手動編寫的HTTP請求相互通信。 我遇到的麻煩是使用StreamReader
從Network 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
,然后可以准確讀取那么多字節的數據 Connection: close
可用於響應,指示在發送所有響應數據后將關閉連接 如您所見, StreamReader.ReadLine()
在解析標頭時會很好地工作,它也非常適合讀取塊,但不能用於讀取固定長度的正文。
我不知道從以前由StreamReader
讀取的流中讀取數據(它可以將一些數據提前讀取到其緩沖區中)是多么可行,但是using
圍繞它們的塊進行拍打只會導致底層流被關閉,除非您選擇一個構造函數重載 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.