String message = URLEncoder.encode("my message", "UTF-8");
try {
// instantiate the URL object with the target URL of the resource to
// request
URL url = new URL("http://www.example.com/comment");
// instantiate the HttpURLConnection with the URL object - A new
// connection is opened every time by calling the openConnection
// method of the protocol handler for this URL.
// 1. This is the point where the connection is opened.
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// set connection output to true
connection.setDoOutput(true);
// instead of a GET, we're going to send using method="POST"
connection.setRequestMethod("POST");
// instantiate OutputStreamWriter using the output stream, returned
// from getOutputStream, that writes to this connection.
// 2. This is the point where you'll know if the connection was
// successfully established. If an I/O error occurs while creating
// the output stream, you'll see an IOException.
OutputStreamWriter writer = new OutputStreamWriter(
connection.getOutputStream());
// write data to the connection. This is data that you are sending
// to the server
// 3. No. Sending the data is conducted here. We established the
// connection with getOutputStream
writer.write("message=" + message);
// Closes this output stream and releases any system resources
// associated with this stream. At this point, we've sent all the
// data. Only the outputStream is closed at this point, not the
// actual connection
writer.close();
// if there is a response code AND that response code is 200 OK, do
// stuff in the first if block
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// OK
// otherwise, if any other status code is returned, or no status
// code is returned, do stuff in the else block
} else {
// Server returned HTTP error code.
}
} catch (MalformedURLException e) {
// ...
} catch (IOException e) {
// ...
}
Die ersten drei Antworten auf Ihre Fragen werden im obigen Beispiel-HTTP-POST neben jeder Methode als Inline-Kommentare aufgeführt.
Von getOutputStream :
Gibt einen Ausgabestream zurück, der in diese Verbindung schreibt.
Grundsätzlich denke ich, dass Sie ein gutes Verständnis dafür haben, wie dies funktioniert. Lassen Sie mich dies nur in Laienbegriffen wiederholen. getOutputStream
öffnet im Grunde einen Verbindungsstrom mit der Absicht, Daten auf den Server zu schreiben. Im obigen Codebeispiel könnte "Nachricht" ein Kommentar sein, den wir an den Server senden und der einen Kommentar darstellt, der in einem Beitrag hinterlassen wurde. Wenn Sie sehen getOutputStream
, öffnen Sie den Verbindungsstrom zum Schreiben, schreiben jedoch erst dann Daten, wenn Sie anrufen writer.write("message=" + message);
.
Von getInputStream () :
Gibt einen Eingabestream zurück, der von dieser offenen Verbindung liest. Eine SocketTimeoutException kann beim Lesen aus dem zurückgegebenen Eingabestream ausgelöst werden, wenn das Lesezeitlimit abläuft, bevor Daten zum Lesen verfügbar sind.
getInputStream
macht das Gegenteil. Wie getOutputStream
es eröffnet auch eine Verbindung Strom, aber die Absicht ist , Daten vom Server zu lesen, nicht zu schreiben. Wenn die Verbindung oder das Öffnen des Streams fehlschlägt, wird a angezeigt SocketTimeoutException
.
Wie wäre es mit dem getInputStream? Da ich die Antwort nur bei getInputStream erhalten kann, bedeutet dies, dass ich noch keine Anfrage bei getOutputStream gesendet habe, sondern einfach eine Verbindung hergestellt habe?
Beachten Sie, dass das Senden einer Anfrage und das Senden von Daten zwei verschiedene Vorgänge sind. Wenn Sie getOutputStream oder getInputStream aufrufen url.openConnection()
, senden Sie eine Anforderung an den Server, um eine Verbindung herzustellen. Es tritt ein Handshake auf, bei dem der Server eine Bestätigung an Sie zurücksendet, dass die Verbindung hergestellt wurde. Zu diesem Zeitpunkt sind Sie dann bereit, Daten zu senden oder zu empfangen. Daher müssen Sie getOutputStream nicht aufrufen, um eine Verbindung zum Öffnen eines Streams herzustellen , es sei denn , Sie möchten Daten senden, um Daten anzufordern.
Für Laien ist eine getInputStream
Anfrage gleichbedeutend mit einem Anruf beim Haus Ihres Freundes, um zu sagen: "Hey, ist es in Ordnung, wenn ich vorbeikomme und mir diese beiden Schraubstöcke ausleihe?" und dein Freund stellt den Händedruck her, indem er sagt: "Sicher! Komm und hol ihn dir". Dann, an diesem Punkt, wird die Verbindung hergestellt, Sie gehen zum Haus Ihres Freundes, klopfen an die Tür, fordern die Schraubstöcke an und gehen zurück zu Ihrem Haus.
Wenn Sie ein ähnliches Beispiel für verwenden getOutputStream
, rufen Sie Ihren Freund an und sagen: "Hey, ich habe das Geld, das ich Ihnen schulde. Kann ich es Ihnen schicken?" Ihr Freund, der Geld braucht und krank ist, dass Sie es so lange aufbewahrt haben, sagt: "Sicher, kommen Sie über Ihren billigen Bastard hinweg." Also gehst du zum Haus deines Freundes und "postest" das Geld an ihn. Dann tritt er dich raus und du gehst zurück zu deinem Haus.
Lassen Sie uns nun mit dem Beispiel des Laien einige Ausnahmen betrachten. Wenn Sie Ihren Freund angerufen haben und er nicht zu Hause war, könnte dies ein Fehler von 500 sein. Wenn Sie angerufen haben und eine Nachricht mit nicht verbundener Nummer erhalten haben, weil Ihr Freund es satt hat, ständig Geld zu leihen, wurde diese 404-Seite nicht gefunden. Wenn Ihr Telefon tot ist, weil Sie die Rechnung nicht bezahlt haben, kann dies eine IOException sein. (HINWEIS: Dieser Abschnitt ist möglicherweise nicht 100% korrekt. Er soll Ihnen eine allgemeine Vorstellung davon geben, was in Laienbegriffen geschieht.)
Frage 5:
Ja, Sie haben Recht, dass openConnection einfach ein neues Verbindungsobjekt erstellt, es jedoch nicht herstellt. Die Verbindung wird hergestellt, wenn Sie entweder getInputStream oder getOutputStream aufrufen.
openConnection
erstellt ein neues Verbindungsobjekt. Aus den URL.openConnection-Javadocs :
Eine neue Verbindung wird jedes Mal geöffnet, indem die openConnection-Methode des Protokollhandlers für diese URL aufgerufen wird.
Die Verbindung wird hergestellt, wenn Sie openConnection aufrufen, und InputStream, OutputStream oder beide werden aufgerufen, wenn Sie sie instanziieren.
Frage 6 :
Um den Overhead zu messen, wickle ich im Allgemeinen einen sehr einfachen Timing-Code um den gesamten Verbindungsblock, wie folgt:
long start = System.currentTimeMillis();
log.info("Time so far = " + new Long(System.currentTimeMillis() - start) );
// run the above example code here
log.info("Total time to send/receive data = " + new Long(System.currentTimeMillis() - start) );
Ich bin sicher, dass es fortgeschrittenere Methoden zum Messen der Anforderungszeit und des Overheads gibt, aber dies ist im Allgemeinen für meine Anforderungen ausreichend.
Informationen zum Schließen von Verbindungen, nach denen Sie nicht gefragt haben, finden Sie unter In Java, wann wird eine URL-Verbindung geschlossen? .
Returns an output stream that writes to this connection.
undReturns an input stream that reads from this open connection.
. Der Ausgangsstrom und der Eingangsstrom sind von der Verbindung getrennt.Tim Bray präsentierte Schritt für Schritt eine kurze Beschreibung, dass openConnection () keine tatsächliche Verbindung herstellt. Eine tatsächliche HTTP-Verbindung wird erst hergestellt, wenn Sie Methoden wie getInputStream () oder getOutputStream () aufrufen.
http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection
quelle
Auf dem in der URL angegebenen Port, falls vorhanden, andernfalls 80 für HTTP und 443 für HTTPS. Ich glaube das ist dokumentiert.
Wenn Sie getInputStream () oder getOutputStream () oder getResponseCode () aufrufen, ohne eine Ausnahme zu erhalten.
Nein und keine.
Einer von ihnen stellt bei Bedarf zuerst eine Verbindung her und gibt dann den erforderlichen Stream zurück.
Siehe oben.
Ja.
Verbinden: Nehmen Sie sich die Zeit, die getInoutStream () oder getOutputStream () benötigt, um zurückzukehren, je nachdem, was Sie zuerst aufrufen. Lesen: Zeit vom ersten Lesen bis zum Abrufen der EOS.
quelle
An welchem Punkt versucht HTTPURLConnection, eine Verbindung zur angegebenen URL herzustellen?
Es lohnt sich zu klären, es gibt die 'UrlConnection'-Instanz und dann die zugrunde liegende Tcp / Ip / SSL-Socket-Verbindung , zwei verschiedene Konzepte. Die Instanz 'UrlConnection' oder 'HttpUrlConnection' ist gleichbedeutend mit einer einzelnen HTTP-Seitenanforderung und wird erstellt, wenn Sie url.openConnection () aufrufen. Wenn Sie jedoch mehrere url.openConnection () von einer URL-Instanz aus ausführen, werden sie mit etwas Glück denselben Tcp / Ip-Socket und dasselbe SSL-Handshake-Material wiederverwenden ... was gut ist, wenn Sie es sind Viele Seitenanforderungen an denselben Server senden, besonders gut, wenn Sie SSL verwenden, bei dem der Aufwand für die Einrichtung des Sockets sehr hoch ist.
Siehe: Implementierung von HttpURLConnection
quelle
Ich habe die Übung zum Erfassen des Paketaustauschs auf niedriger Ebene durchlaufen und festgestellt, dass die Netzwerkverbindung nur durch Vorgänge wie getInputStream, getOutputStream, getResponseCode, getResponseMessage usw. ausgelöst wird.
Hier ist der Paketaustausch erfasst, wenn ich versuche, ein kleines Programm zum Hochladen von Dateien in Dropbox zu schreiben.
Unten ist mein Spielzeugprogramm und meine Anmerkung
quelle