Sto implementando un semplice client HTTP che si collega a un server Web e ottiene la sua homepage predefinita. Qui è bello e funziona:Client HTTP davvero strano che utilizza TcpClient in C#
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();
}
}
}
Quando si elimina la riga sottostante dall'alto codice, i blocchi di programma su sr.ReadToEnd.
req += "Host: www.google.com\r\n";
Ho anche sostituito sr.ReadToEnd con sr.Read, ma non può leggere nulla. Ho usato Wireshark per vedere che cosa sono accado:
Come potete vedere, dopo la mia richiesta GET Google non risponde e la richiesta viene ritrasmessa ancora e ancora. Sembra che dobbiamo specificare la parte dell'host nella richiesta HTTP. La parte strana è NOI NON LO. Ho usato telnet per inviare questa richiesta e ho ricevuto risposta da Google. Ho anche catturato la richiesta inviata da telnet ed era esattamente uguale alla mia richiesta.
Ho provato molti altri siti Web (ad esempio Yahoo, Microsoft) ma il risultato è lo stesso.
Quindi, il ritardo in telnet causa il comportamento del server Web in modo diverso (perché in telnet effettivamente digitare caratteri invece di inviarli insieme in 1 pacchetto).
Un altro problema è strano quando cambio HTTP/1.0 a HTTP/1.1, il programma sempre blocchi sulla sr.ReadToEnd linea. Immagino sia perché il server web non chiude la connessione.
Una soluzione sta usando Leggi (o ReadLine) e ns.DataAvailable leggere la risposta. Ma non posso essere sicuro di aver letto tutta la risposta. Come posso leggere la risposta ed essere sicuro che non ci siano più byte rimasti nella risposta di una richiesta HTTP/1.1?
Nota: Come dice W3,
the Host request-header field MUST accompany all HTTP/1.1 requests
(e l'ho fatto per la mia HTTP/1.1 richieste). Ma non ho visto nulla del genere per HTTP/1.0. Inoltre, l'invio di una richiesta senza l'intestazione Host tramite telnet funziona senza problemi.
Aggiornamento:
push flag è stato impostato a 1 nel segmento TCP. Ho anche provato winsock netsh reset per resettare il mio stack TCP/IP. Non ci sono firewall o anti-virus sul computer di prova. Il pacchetto viene effettivamente inviato perché Wireshark installato su un altro computer può catturarlo.
Ho anche provato altre richieste. Per esempio,
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";
In tutti i tipi di richieste, se tralascio l'Ostia : parte, il web-server non risponde e se con un Host: parte, anche una richiesta non valida (solo come la richiesta di cui sopra) sarà risposto (da un 400: HTTP Bad Request).
nos dice che la parte Host: non è richiesta sulla sua macchina, e questo rende la situazione più strana.
Non so se questo è il problema, ma non si dovrebbe utilizzare il contenuto di lunghezza nella risposta HTTP per determinare il numero di byte si dovrebbe leggere, e quindi leggere quei molti byte dal corpo della risposta ? – Aziz
@Aziz. Forse questa è una buona soluzione invece di usare ** ReadToEnd **. Ma nella prima parte della domanda non ricevo nulla (nemmeno un byte) dal server. – Isaac
Quel codice funziona qui con o senza l'intestazione Host :. Il segmento TCP della richiesta GET imposta il bit PUSH? - Non che tu possa fare molto su di esso ma se non è impostato potrebbe spiegare le ritrasmissioni – nos