communityWir suchen ständig neue Tutorials und Artikel! Habt ihr selbst schonmal einen Artikel verfasst und seid bereit dieses Wissen mit der Community zu teilen? Oder würdet ihr gerne einmal über ein Thema schreiben das euch besonders auf dem Herzen liegt? Dann habt ihr nun die Gelegenheit eure Arbeit zu veröffentlichen und den Ruhm dafür zu ernten. Schreibt uns einfach eine Nachricht mit dem Betreff „Community Articles“ und helft mit das Angebot an guten Artikeln zu vergrößern. Als Autor werdet ihr für den internen Bereich freigeschaltet und könnt dort eurer literarischen Ader freien Lauf lassen.

TCP/IP Socket-Programmierung in C# - Formulare im Internet senden Drucken E-Mail
Benutzerbewertung: / 1025
SchwachPerfekt 
Geschrieben von: Kristian   
Sonntag, den 12. März 2006 um 02:20 Uhr
Beitragsseiten
TCP/IP Socket-Programmierung in C#
Daten senden und empfangen
Höhere Socketklassen
Multicast und Broadcast
Ping, Threads und asynchrone Sockets
Formulare im Internet senden
E-Mail verschicken
Alle Seiten

Hypertext Transfer Protocol (HTTP)

Zu den wesentlichen Operationen im Internet gehört das Ausfüllen und Versenden von Formularen. Ob es sich um eine Suchanfrage bei einer Suchmaschine handelt oder der Registrierung in einem Forum, stets sind Formulardaten im Spiel. Grundlage für die Präsentation und Manipulation von Webseiten ist das Hypertext Transfer Protocol (HTTP, dt. Hypertext-Übertragungsprotokoll). Das HTTP ist ein Protokoll zur Übertragung von Daten über ein Netzwerk und wird durch das RFC 2616 beschrieben. Es gehört der sogenannten Anwendungsschicht etablierter Netzwerkmodelle an und befindet sich somit direkt über der Transportschicht, in der das TCP und UDP verankert sind. Die Anwendungsschicht wird von den Anwendungsprogrammen angesprochen, im Fall des HTTP ist dies meistens ein Webbrowser. Im ISO/OSI-Schichtenmodell entspricht die Anwendungsschicht den Schichten 5–7.

Durch Erweiterung seiner Anfragemethoden, Header-Informationen und Statuscodes ist das HTTP nicht auf Hypertext beschränkt, sondern wird zunehmend zum Austausch beliebiger Daten verwendet. Zur Kommunikation ist HTTP auf ein zuverlässiges Transportprotokoll angewiesen. In nahezu allen Fällen wird hierfür das Transmission Control Protocol (TCP) verwendet.

Das HTTP wurde 1989 von Tim Berners-Lee am CERN zusammen mit der URL und der Hypertext Markup Language (HTML) entwickelt, wodurch praktisch das World Wide Web geboren wurde. Es wird hauptsächlich eingesetzt, um Webseiten aus dem World Wide Web (WWW) in einen Webbrowser zu laden. Die Flexibilität von HTTP hat dazu geführt, dass heute zahlreiche Netzwerkprotokolle, wie SOAP (ursprünglich für Simple Object Access Protocol), auf HTTP aufbauen.

Aufbau

Die Kommunikationseinheiten im HTTP zwischen Client und Server werden als Nachrichten bezeichnet, von denen es zwei unterschiedliche Arten gibt: die Anfrage (engl. Request) vom Client an den Server und die Antwort (engl. Response) als Reaktion darauf vom Server zum Client.

http-request

Jede Nachricht besteht dabei aus zwei Teilen, dem Nachrichtenkopf (engl. Message Header, kurz: Header oder auch HTTP-Header genannt) und dem Nachrichtenkörper (engl. Message Body, kurz: Body). Der Nachrichtenkopf enthält wichtige Informationen über den Nachrichtenkörper wie etwa verwendete Kodierungen oder den Inhaltstyp, damit dieser vom Empfänger korrekt interpretiert werden kann. Der Nachrichtenkörper enthält schließlich die Nutzdaten.

POST und GET

Häufig will der Nutzer einer Website spezielle Informationen senden. Dazu stellt HTTP prinzipiell zwei Möglichkeiten zur Verfügung. Beim sogenannten HTTP-GET sind die Daten Teil der URL und bleiben deshalb beim Speichern oder der Weitergabe des Links erhalten. Die zweite Variante nennt sich HTTP-POST. Hier werden die Daten mit einer speziell dazu vorgesehenen Anfrageart in den HTTP-Kopfdaten übertragen, so dass sie in der URL nicht sichtbar sind.

HTTP-GET

Hierbei werden die Parameter-Wertepaare durch das Zeichen ? in der URL eingeleitet.

Oft wird diese Vorgehensweise gewählt, um eine Liste von Parametern zu übertragen, die die Gegenstelle bei der Bearbeitung einer Anfrage berücksichtigen soll. Häufig besteht diese Liste aus mit dem Zeichen & getrennten Wertepaaren, die je aus einem Parameternamen, dem Zeichen = und dem Wert des Parameters bestehen. Seltener wird das Zeichen ; zur Trennung von Einträgen der Liste benutzt.

Ein Beispiel: Das Eingabefeld auf einer Login-Seite hat zwei Felder mit den Namen „user“ und „password“. Der Browser sendet folgende oder ähnliche Anfrage an den Server:

	GET /login.php?user=joe&password=guessme HTTP/1.1
	Host: www.mysite.com
	User-Agent: Mozilla/4.0

Der Aufruf erfolgt direkt über den Uniform Resource Locator (URL), ist also in der Adresszeile des Browsers sichtbar.

HTTP-POST

Da sich die Daten nicht in der URL befinden, können per POST große Datenmengen, z. B. Bilder, übertragen werden.

Im folgenden Beispiel wird wieder ein Login ausgeführt, doch diesmal verwendet der Browser aufgrund eines modifizierten HTML-Codes (method="POST") eine POST-Anfrage. Die Variablen stehen dabei nicht in der URL, sondern gesondert im Body-Teil, etwa:

	POST /login.php HTTP/1.1
	Host: www.mysite.com
	User-Agent: Mozilla/4.0
	Content-Length: 27
	Content-Type: application/x-www-form-urlencoded

	user=joe&password=guessme

Alle zu übertragenden Daten müssen ggf. URL-kodiert werden, d. h. reservierte Zeichen müssen mit „%“ und Leerzeichen mit „+“ dargestellt werden.

HttpWebRequest und HttpWebResponse

Im .NET Framework gibt es zwei Basisklassen für den Umgang mit HTTP. Sinngemäß nennen sie sich HttpWebRequest und HttpWebResponse. Auch diese Klassen setzen direkt auf Sockets auf und ermöglichen einen abstrakten, bequemen Umgang mit dem Hypertext-Übertragungsprotokoll. Die Klassen generieren implizit die notwendigen TCP-Sockets und senden bzw. empfangen die spezifizierten Daten.

Wie man einen HTTP-GET auf Socketebene ausführt, haben Sie bereits in einem vorangegangenen Kapitel erfahren. In dem Codebeispiel HTTPGet wurde eine Zeichenkette verwendet, um über einen offenen TCP-Socket eine HTTP/1.1 Anfrage an den Server zu senden. Diese Anfrage beantwortet der Server standardmäßig mit der Ausstrahlung der Startseite der angeforderten Webseite. Die Klasse HttpWebRequest erspart Ihnen die Konstruktion des TCP-Sockets und alle weiteren Details. Stattdessen legen Sie mit dem Property Method die Art des Requests fest und geben anschließend nur noch die Anfrage selbst an. Mithilfe von GetRequestStream lässt sich die Antwort des Servers anschließend direkt auslesen.

Wir wollen nach der Theorie nun mit C# ein Formular ausfüllen. Auf der Seite http://www.codeplanet.eu/files/post/index.html steht hierfür ein einfaches Post Formular bereit.

post-form

Das Formular besitzt den folgenden HTML-Quelltext:

 
<form action="form.php" method="POST">
    <table>
    <tr>
        <td>Name:</td>
        <td><input type="text" name="name"></td>
    </tr>
    <tr>
        <td>Email:</td>
        <td><input type="text" name="email"></td>
    </tr>
    <tr>
        <td>Nachricht:</td>
        <td><textarea name="msg"></textarea></td>
    </tr>
    <tr>
        <td><input type="submit" name="submitform" value="Senden"></td>
    </tr>
<form> 
 

Es lässt sich erkennen, dass das Formular drei Eingabefelder besitzt. Jedes Eingabefeld trägt einen Namen. Diese Namen sind bei einem HTTP-Request von Bedeutung. Sobald der Benutzer den Sendebutton betätigt, wird per POST das PHP-Skript form.php aufgerufen. Das Skript verwertet die per POST übermittelten Daten und gibt diese formatiert aus. Sie können das im Originalformular ausprobieren.

Das folgende Beispiel generiert POST-Daten und sendet sie mit HttpWebRequest an das genannte Skript. Anschließend wird mithilfe von HttpWebResponse die Antwort des Servers empfangen und der Quelltext der Antwort auf der Konsole ausgegeben.

using System;
using System.Net;
using System.Text;
using System.IO;
 
namespace CodePlanet.Articles.ProgrammingSockets
{
    /// <summary>
    /// Demonstriert einen HTTP-Post. Füllt ein Formular
    /// im Internet aus und empfängt die Antwort als HTML-Quelltext.
    /// </summary>
    public class HTTPPostExample
    {
        public static void Main(string[] args)
        {
            // Setze den Uniform Resource Identifier.
            Uri uri = new Uri("http://www.codeplanet.eu/files/post/form.php");
            // Generiere einen Request mit einer Adresse, die einen POST erwartet.
            WebRequest request = WebRequest.Create(uri);
            // Setze die Methodeneigenschaft des Request auf POST.
            request.Method = "POST";
            // Generiere die POST Daten und konvertiere sie in ein byte Array.
            string postData = "submitform=Senden&" +
                              "name=Max Mustermann&" +
                              "email=max\@muster.com&" +
                              "msg=Hello my dear friend, how are you?";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            // Setze die ContentType Eigenschaft von WebRequest.
            request.ContentType = "application/x-www-form-urlencoded";
            // Setze die ContentLength Eigenschaft von WebRequest.
            request.ContentLength = byteArray.Length;
            // Empfange den Request Stream.
            Stream dataStream = request.GetRequestStream();
            // Schreibe die Daten in den Request Stream.
            dataStream.Write(byteArray, 0, byteArray.Length);
            // Schließe das Stream Objekt.
            dataStream.Close();
            // Empfange die Antwort.
            WebResponse response = request.GetResponse();
            // Zeige den Status an.
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            // Empfange den Stream mit dem Inhalt vom Server.
            dataStream = response.GetResponseStream();
            // Öffne den Stream mit dem StreamReader.
            StreamReader reader = new StreamReader(dataStream);
            // Lese den Inhalt.
            string responseFromServer = reader.ReadToEnd();
            // Zeige den Inhalt in der Konsole an.
            Console.WriteLine(responseFromServer);
            // Schließe alle Streams.
            reader.Close();
            dataStream.Close();
            response.Close();
        }
    }
}

Cookies

Ein Problem bei HTTP ist das Informationen aus früheren Anforderungen verloren (zustandsloses Protokoll) gehen. Über Cookies in den Header-Informationen können aber Anwendungen realisiert werden, die Statusinformationen (Benutzereinträge, Warenkörbe) zuordnen können. Dadurch werden Anwendungen möglich, die Status- bzw. Sitzungseigenschaften erfordern. Auch eine Benutzerauthentifizierung ist möglich.

Ein HTTP-Cookie, auch Browser-Cookie genannt (engl., „Plätzchen“, „Keks“), bezeichnet Informationen, die ein Webserver zu einem Browser sendet oder die clientseitig durch JavaScript erzeugt werden. Der Client sendet die Informationen in der Regel bei späteren Zugriffen an denselben Webserver im Hypertext-Transfer-Protocol-Header an den Server. Cookies sind clientseitig persistente/gespeicherte Daten und werden im RFC 2965 detailliert beschrieben.

Im nachfolgenden Beispiel bittet der Server den Clienten mit der „Set-Cookie“-Zeile, sich Daten zu merken:

	HTTP/1.0 200 OK
	Set-Cookie: letzteSuche="cookie aufbau";
	            expires=Tue, 29-Mar-2005 19:30:42 GMT;
	            Max-Age=2592000;
	            Path=/cgi/suche.py;
	            Version="1"

Cookies kommen im Internet sehr oft zur Anwendung. Denken Sie an die Anmeldung in einem Internetforum, bei der die Sitzung gespeichert werden soll. Sie können Ihren Rechner herunterfahren und die Seite zu einem späteren Zeitpunkt erneut besuchen. Wenn Sie die Speicherung von Cookies mit Ihrem Webbrowser gestattet haben, müssen Sie sich nicht erneut anmelden. Der Webbrowser sendet einfach die Identifikationsdaten, die im Cookie gespeichert sind, an den Server.

Das unten gezeigte Beispiel demonstriert die Anmeldung in unserem Forum. Die POST-Daten für den Login setzen sich aus dem Forennamen und dem Passwort zusammen. Das Passwort wird als MD5-Hash versendet. Die statische Methode getMd5Hash generiert aus einer beliebigen Zeichenkette den Hashwert. Das Programm sendet die Formulardaten an den Server von CodePlanet und meldet sich im Forum an. Parallel dazu werden die Cookiedaten empfangen und ihr Inhalt auf der Kommandozeile ausgegeben.

using System;
using System.Net;
using System.Text;
using System.IO;
using System.Security.Cryptography;
 
namespace CodePlanet.Articles.ProgrammingSockets
{
    /// <summary>
    /// Demonstriert den Login auf einem Internet-Portal,
    /// in diesem Fall im CodePlanet Forum.
    /// </summary>
    public class HTTPWebResponse
    {
        public static void Main(string[] args)
        {
            string loginname = "User";
            string password = "Password";
            string uri = "http://codeplanet.eu/forum/login.php?do=login";
            string loginData = "vb_login_username=" +
                               loginname +
                               "&vb_login_password=&s=&do=login&vb_login_md5password=" +
                               getMd5Hash(password) +
                               "&vb_login_md5password_utf=" +
                               getMd5Hash(password);
 
            HttpWebResponse webResponse = DoLogin(uri, loginData);
            ShowCookie(webResponse);
        }
 
        public static HttpWebResponse DoLogin(string loginUri, string loginData)
        {
            // Der cookieContainer speichert den Cookie beim Login
            CookieContainer cookieContainer = new CookieContainer();
            // Klicke zuerst auf die Login Seite
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(loginUri);
            // Identifiziere dich als Mozilla Firefox 2.0
            req.UserAgent = "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1";
            req.CookieContainer = cookieContainer;
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            ASCIIEncoding encoding = new ASCIIEncoding();
            byte[] loginDataBytes = encoding.GetBytes(loginData);
            req.ContentLength = loginDataBytes.Length;
            Stream stream = req.GetRequestStream();
            stream.Write(loginDataBytes, 0, loginDataBytes.Length);
            stream.Close();
            return (HttpWebResponse)req.GetResponse();
        }
 
        public static void ShowCookie(HttpWebResponse res)
        {
            // Gebe die Details des Cookies aus
            foreach (Cookie cook in res.Cookies) {
                Console.WriteLine("Cookie:");
                Console.WriteLine("{0} = {1}", cook.Name, cook.Value);
                Console.WriteLine("Domain: {0}", cook.Domain);
                Console.WriteLine("Path: {0}", cook.Path);
                Console.WriteLine("Port: {0}", cook.Port);
                Console.WriteLine("Secure: {0}", cook.Secure);
 
                Console.WriteLine("When issued: {0}", cook.TimeStamp);
                Console.WriteLine("Expires: {0} (expired? {1})", cook.Expires, cook.Expired);
                Console.WriteLine("Don't save: {0}", cook.Discard);
                Console.WriteLine("Comment: {0}", cook.Comment);
                Console.WriteLine("Uri for comments: {0}", cook.CommentUri);
                Console.WriteLine("Version: RFC {0}", cook.Version == 1 ? "2109" : "2965");
 
                Console.WriteLine("String: {0}", cook.ToString());
            }
        }
 
        // Hashe einen string und generiere einen 32 Zeichen langen Hex-Hash.
        public static string getMd5Hash(string input)
        {
            // Generiere ein MD5CryptoServiceProvider Objekt
            MD5 md5Hasher = MD5.Create();
 
            // Konvertiere den Eingabestring in ein byte[] und berechne den Hash
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
 
            StringBuilder sBuilder = new StringBuilder();
 
            for (int i = 0; i < data.Length; i++) {
                sBuilder.Append(data[i].ToString("x2"));
            }
 
            return sBuilder.ToString();
        }
    }
}

Wie Sie wahrscheinlich bereits erkannt haben, ist es für den korrekten Aufruf der Daten erforderlich den Aufbau des entsprechenden Formulars zu kennen. Der Aufbau lässt sich dem Quelltext der Webseite entnehmen. Eine einfachere Variante nutzt ein Programm zur Netzwerkanalyse, mit dem sich die Netzwerk-Kommunikationsverbindungen zwischen Webbrowser und Server direkt beobachten lassen. Dazu müssen Sie in Ihrem Webbrowser lediglich das gewünschte Formular ausfüllen und absenden. Anschließend lassen sich, z.B. mithilfe von Wireshark oder dem Firefox-Plugin Firebug die vom Webbrowser übertragenen Formulardaten direkt einsehen. Insbesondere komplexere Formulare können so in der Praxis schnell erfasst werden ohne sich detailliert mit dem HTML-Quelltext auseinander setzen zu müssen.



Zuletzt aktualisiert am Donnerstag, den 02. Januar 2014 um 23:03 Uhr
 
AUSWAHLMENÜ