Я реализую простой HTTP-клиент, который просто подключается к веб-серверу и получает его домашнюю страницу по умолчанию. Вот и она работает хорошо:
using System;
using System.Net.Sockets;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TcpClient tc = new TcpClient();
tc.Connect("www.google.com", 80);
using (NetworkStream ns = tc.GetStream())
{
System.IO.StreamWriter sw = new System.IO.StreamWriter(ns);
System.IO.StreamReader sr = new System.IO.StreamReader(ns);
string req = "";
req += "GET / HTTP/1.0\r\n";
req += "Host: www.google.com\r\n";
req += "\r\n";
sw.Write(req);
sw.Flush();
Console.WriteLine("[reading...]");
Console.WriteLine(sr.ReadToEnd());
}
tc.Close();
Console.WriteLine("[done!]");
Console.ReadKey();
}
}
}
Когда я удаляю приведенную ниже строку из кода выше, программа блокируется на sr.ReadToEnd .
req += "Host: www.google.com\r\n";
Я даже заменил sr.ReadToEnd на sr.Read , но он ничего не может прочитать. Я использовал Wireshark, чтобы увидеть, что случилось:
Скриншот захваченных пакетов с помощью Wireshark http://www.imagechicken.com/uploads/1252514718052893500.jpg
Как видите, после моего запроса GET Google не отвечает, и запрос повторяется снова и снова. Похоже, мы ДОЛЖНЫ указать часть Host в HTTP-запросе. Странная часть МЫ НЕ. Я использовал telnet , чтобы отправить этот запрос и получил ответ от Google. Я также захватил запрос, отправленный telnet, и он был точно таким же, как мой запрос.
Я пробовал много других сайтов (например, Yahoo, Microsoft), но результат тот же.
Таким образом, задержка в telnet заставляет веб-сервер работать иначе (потому что в telnet мы на самом деле печатаем символов вместо того, чтобы отправлять их вместе в 1 пакете).
Другая странная проблема - когда я меняю HTTP / 1.0 на HTTP / 1.1 , программа всегда блокируется в строке sr.ReadToEnd . Я думаю, это потому, что веб-сервер не закрывает соединение.
Одним из решений является использование Read (или ReadLine ) и ns.DataAvailable для чтения ответа. Но я не могу быть уверен, что прочитал все ответы. Как я могу прочитать ответ и убедиться, что в ответе на запрос HTTP / 1.1 больше не осталось байтов?
Примечание:
Как говорит W3,
поле заголовка запроса Host ДОЛЖНО сопровождать все HTTP / 1.1
запросы
(и я сделал это для моих запросов HTTP / 1.1). Но я не видел такой вещи для HTTP / 1.0 . Также отправка запроса без заголовка Host с использованием telnet работает без проблем.
Обновление:
Нажмите флаг был установлен в 1 в сегменте TCP. Я также попытался netsh winsock reset , чтобы сбросить мой стек TCP / IP. На тестируемом компьютере нет брандмауэров и антивирусов. Пакет фактически отправлен, потому что Wireshark, установленный на другом компьютере, может перехватить его.
Я также попробовал некоторые другие запросы. Например,
string req = "";
req += "GET / HTTP/1.0\r\n";
req += "s df slkjfd sdf/ s/fd \\sdf/\\\\dsfdsf \r\n";
req += "qwretyuiopasdfghjkl\r\n";
req += "Host: www.google.com\r\n";
req += "\r\n";
Во всех видах запросов, если я опускаю часть Host: , веб-сервер не отвечает, а если с частью Host: , даже недопустимый запрос ( так же, как и вышеупомянутый запрос) будет получен ответ (400: HTTP Bad Request).
nos говорит, что Host: часть не требуется на его машине, и это делает ситуацию более странной.