Client-Server-Modell |
![]() |
![]() |
![]() |
Dienstag, den 24. August 2010 um 11:20 Uhr | ||||||||||||||||||||||||||||||||||||||||||||
Seite 1 von 2
EinführungDieser Artikel basiert im Wesentlichen auf dem Tutorial „TCP/IP Socket-Programmierung in C#“ und setzt die dort vermittelten Kenntnisse in ein fortschrittliches Client-Server-Modell um. Ziel ist es mithilfe eines Clienten Daten von einem entfernten Server abfragen zu können. Der Server soll diese Daten an einen oder mehrere Clienten gleichzeitig senden können und somit asynchron arbeiten. Die Daten liegen als XML-Dokument vor und werden vom Server nur bei Bedarf „on the fly“ übermittelt. Damit wird zum einen gezeigt, wie sich die Belastung für den Server im Upstream senken lässt und zum anderen eröffnet es die Möglichkeit die Funktion von einfachen Netzwerkprotokollen zu demonstrieren. Netzwerkprotokolle sind exakte Vereinbarungen, nach der Daten zwischen Computern bzw. Prozessen ausgetauscht werden, die durch ein Netz miteinander verbunden sind. Chatprogramme und auch Browser greifen auf Protokolle zurück, um im Internet zu kommunizieren. Als Beispiel wurden in diesem Artikel Kontaktdaten von natürlichen Personen gewählt. Diese Daten werden in einem XML-Dokument gespeichert und vom Server an die Clienten übertragen. Da der Server im Zentrum des Netzwerks steht, kann er Ressourcen verwalten, die allen Usern gemeinsam sind, um Probleme der Redundanz und Widersprüchlichkeit zu vermeiden. Die Clienten können die Kontaktliste vom Server empfangen und auch mit verschiedenen Befehlen detaillierte Daten aus der Kontaktliste abfragen. Das Projekt wurde mit Microsoft Visual Studio und dem .NET Framework 4.0 realisiert. ![]() XMLXML ist eine Auszeichnungssprache zur Darstellung hierarchisch strukturierter Daten in Form von Textdaten. XML wird u. a. für den plattform- und implementationsunabhängigen Austausch von Daten zwischen Computersystemen eingesetzt, insbesondere über das Internet. Die Extensible Markup Language wurde in einem Standard vom World Wide Web Consortium (W3C) spezifiziert. Die vom W3C herausgegebene XML-Spezifikation (Recommendation, erste Ausgabe vom 10. Februar 1998, aktuell ist die fünfte Ausgabe vom 26. November 2008) definiert dabei eine Metasprache, auf deren Basis durch strukturelle und inhaltliche Einschränkungen anwendungsspezifische Sprachen definiert werden. Diese Einschränkungen werden durch Schemasprachen wie DTD oder XML Schema ausgedrückt. Beispiele für XML-Sprachen sind: RSS, MathML, GraphML, XHTML, XAML, Scalable Vector Graphics (SVG), aber auch XML-Schema. Die Webtechnologie Ajax ist heute im Internet oft anzutreffen und basiert ebenfalls auf XML. Ajax ist ein Apronym für die Wortfolge „Asynchronous JavaScript and XML“. Es bezeichnet ein Konzept der asynchronen Datenübertragung zwischen einem Browser und dem Server. Dieses ermöglicht es, HTTP-Anfragen durchzuführen, während eine HTML-Seite angezeigt wird, und die Seite zu verändern, ohne sie komplett neu zu laden. KontaktlisteIn dem Client-Server-Modell soll der entfernte Server Kontaktdaten übertragen, die in einem XML-Dokument lokal abgespeichert sind. In diesem Dokument kann eine Stelle zu beliebigen Zeitpunkten Kontakte hinterlegen und die Clienten können anschließend diese Kontakte von überall auf der Welt abfragen. Wichtig für die Übertragung der Daten ist das sowohl Server als auch Client wissen welche Daten überhaupt vorhanden sind. Die Beschreibung der Kontaktliste mit den Elementen ist daher der erste logische Schritt bei dem Entwurf der Applikation. Typisch für ein XML-Dokument ist das es aus Textzeichen besteht, im einfachsten Fall ASCII, so dass es damit menschenlesbar – Binärdaten enthält es per Definition nicht - wird. XML-Dokumente besitzen einen physischen und einen logischen Aufbau. Der logische Aufbau entspricht einer Baumstruktur und ist damit hierarchisch organisiert. Als Baumknoten gibt es Elemente, deren physische Auszeichnung mittels einem passenden Paar aus Start-Tag ( Ein einzelner Kontakt in dem Programm besteht aus der Identifikationsnummer des Mitarbeiters, kurz Id, dem Namen, der Firma bei der der Mitarbeiter angestellt ist, seiner Adresse, der E-Mail, der Telefon-, Fax- und Handynummer, der Anrede, dem Titel und der Position innerhalb des Unternehmens. Nachfolgend ist so eine Kontaktliste mit drei Beispielkontakten aufgelistet. <Contacts xmlns="http://tempuri.org/Contacts.xsd"> <Kontakte> <Id>1</Id> <Name>Stefan Müller</Name> <Firma>Lufthansa AG</Firma> <Adresse>Elfenbeinstrasse 25, 80935 München</Adresse> <Email>stefanmueller@mail.de</Email> <Telefon>98362550</Telefon> <Handy>01746352423</Handy> <Fax>98362551</Fax> <Anrede>Herr</Anrede> <Titel>Dipl.-Ing. (FH)</Titel> <Position>Abteilungsleiter</Position> </Kontakte> <Kontakte> <Id>2</Id> <Name>Barbara Bauer</Name> <Firma>BMW</Firma> <Adresse>Burgstrasse 2, 14935 Berlin</Adresse> <Email>barbara@bmw.de</Email> <Telefon>82272550</Telefon> <Handy>017463764254</Handy> <Fax>0892272573</Fax> <Anrede>Frau</Anrede> <Titel>Dr.</Titel> <Position>Mitarbeiterin</Position> </Kontakte> <Kontakte> <Id>3</Id> <Name>John Doe</Name> <Firma>Doe Inc.</Firma> <Adresse>Evergreen 345, 10101 New York</Adresse> <Email>john@doe.de</Email> <Telefon>10001</Telefon> <Handy>10002</Handy> <Fax>10003</Fax> <Anrede>Herr</Anrede> <Titel>Prof.</Titel> <Position>Dozent</Position> </Kontakte> </Contacts> Damit wären die Daten beschrieben, die im Client-Server-Modell ausgetauscht werden sollen. NetzwerkprotokollEin Netzwerkprotokoll im Prinzip eine Vereinbarung aus einem Satz von Regeln und Formaten (Syntax), die das Kommunikationsverhalten der kommunizierenden Instanzen in den Computern bestimmen (Semantik). Das Internet basiert auf dem OSI-Schichtenmodell, das die Aufgaben der Kommunikation in sieben aufeinander aufbauende Schichten unterteilt. Für jede Schicht existiert eine Beschreibung, in welcher steht, was diese Schicht zu leisten hat. Diese Anforderungen müssen von den Kommunikationsprotokollen realisiert werden. Die konkrete Umsetzung wird dabei nicht vorgegeben und kann daher sehr unterschiedlich sein. Somit existieren mittlerweile für jede der sieben Schichten zahlreiche solcher Protokolle. Das hier vorgestellte Client-Server-Modell nutzt das Transmission Control Protocol (TCP) für den Datenaustausch als Transportprotokoll. TCP ist Bestandteil der Transportschicht im OSI-Schichtenmodell. Anwendungsprogramme nutzen Transportprotokolle und definieren zusätzlich ein eigenes Protokoll, das in der sogenannten Anwendungsschicht verankert ist. So muss das Programm beim Datenaustausch die über TCP gesendeten Daten interpretieren können. Das Hypertext Transfer Protocol ist ein bekanntes Protokoll aus der Anwendungsschicht und wird von allen Browsern unterstützt. Alle Programme im Internet basieren auf dem Internet Protocol. In diesem Artikel wird das neue Internet Protocol Version 6 (IPv6) genutzt. Die Entwicklung von eigenen Kommunikationsprotokollen kann sehr komplex und zeitaufwändig sein. Instant Messenger, wie ICQ oder Skype, basieren auf großen Protokollen, wie dem OSCAR-Protokoll (Open System for Communication in Realtime). OSCAR, welches von AOL urspründlich für den AOL Instant Messenger (AIM) entwickelt wurde und nach der Übernahme von ICQ für beide Messenger verwendet wird, arbeitet ebenfalls auf einer bestehenden TCP-Verbindung. In .NET bietet sich für die Erstellung des Protokolls eine eigene Bibliothek an, die anschließend von Server und Client gleichermaßen verwendet werden kann. Dadurch ist eine Codeduplizierung ausgeschlossen und das Anwendungsprotokoll kann separat weiterentwickelt und verändert werden. Dabei muss immer berücksichtigt werden das jede signifikante Veränderung des Anwendungsprotokolls dazu führt, dass Programme, die auf diesem Protokoll basieren nicht mehr richtig funktionieren. Auch deshalb ist der erste Entwurf des Anwendungsprotokolls von elementarer Bedeutung. Nachrichtentypen definierenVor Beginn der eigentlichen Programmierung müssen die Regeln für das Protokoll festgelegt werden. Welche Nachrichten soll der Client mit dem Server austauschen können und wie müssen die Nachrichten strukturiert sein, um von beiden Seiten richtig interpretiert und auch generiert werden zu können. Triviale Fragen, wie zum Beispiel der Verbindungsauf- und -abbau gehören in diesen Themenbereich. In einer eigenen Klasse mit dem Namen /// <summary> /// Stores all possible packet types in the protocol. /// </summary> public enum PacketType { /// <summary> /// Client asked for a partial contact list. /// </summary> ContactListRequest = 1, /// <summary> /// Client asked for a specific contact. /// </summary> ContactRequest, /// <summary> /// Acknowledged client reply for contact list. /// </summary> ContactListReply, /// <summary> /// Acknowledged client reply for specific contact. /// </summary> ContactReply, /// <summary> /// Perform logout. /// </summary> ClientExit, /// <summary> /// A simple text message. /// </summary> Message, /// <summary> /// Broadcast a message to all clients. /// </summary> Broadcast, /// <summary> /// A login message. /// </summary> ClientLoginInformation, /// <summary> /// Client gone. /// </summary> ClientLogOffInformation, /// <summary> /// Request a full client list. /// </summary> SendClientList, /// <summary> /// Routes a message to another address. /// </summary> Route, /// <summary> /// A simple ping. /// </summary> Ping } Nachricht entwerfenPakete spielen im Internet eine zentrale Rolle. Das OSI-Referenzmodell ist ein Protokollstapel bestehend aus fortlaufend nummerierte Schichten. Jede Schicht benutzt dabei zur Erfüllung ihrer speziellen Aufgabe die jeweils tiefere Schicht im Protokollstapel. Daten, die über ein Netz übertragen werden, werden von einem Netzprotokoll des Stapels nach dem anderen verarbeitet. Jedes Netzprotokoll entfernt beim Empfang aus den Daten diejenigen Steuerinformationen, die nur für dieses Protokoll selbst bestimmt sind, und übergibt die verbliebenen Daten dem nächsthöheren Netzprotokoll. In der Senderichtung werden die Steuerinformationen hinzugefügt, bevor sie dem nächsttieferen Netzprotokoll übergeben werden - eine Nachricht trägt also auf der Leitung sämtliche Header der darüberliegenden Schichten. Eine Nachricht, die via Ethernet versandt wird, lässt sich wie folgt veranschaulichen:
Beim Verschicken einer Nachricht über TCP, wird die Nachricht in einem TCP-Segment verpackt, welches wiederum in einem IP-Paket verpackt wird, bevor es die Reise durch das Internet antreten kann. Die Struktur eines Protokollstapels ähnelt dem Aufbau der Materie im Universum. Körper bestehen aus vielen verschiedenen Atomen, deren Kerne Protonen und Neutronen beinhalten, die ihrerseits wieder aus up- und down-Quarks zusammengesetzt sind. Nachrichten können als Datenpakete aufgefasst werden. Ein Datenpaket ist in der Datenverarbeitung ganz allgemein eine der Bezeichnungen für in sich geschlossene Dateneinheiten, die ein Sender oder auch ein sendender Prozess (z. B. ein Server) einem Empfänger sendet (vergl.: Rahmen (Nachrichtentechnik)). Ein solches Datenpaket – im Unterschied zu einem Datenstrom – hat eine wohldefinierte Länge und Form, es kann daher auf Vollständigkeit und Brauchbarkeit geprüft werden. Das Datenpaket besteht i.d.R. aus einem Header (von engl. head = Kopf) mit den Metadaten und einem Payload, das die Nutzdaten beherbergt. Das in diesem Artikel vorgestellte Anwendungsprotokoll setzt, wie bereits erwähnt, auf TCP auf. Das Transmission Control Protocol (TCP) ist ein verbindungsorientiertes Protokoll, welches auf Zuverlässigkeit ausgelegt ist und einen bidirektionalen, byte-orientierten Datenstrom zwischen zwei Endpunkten etabliert. Datenpakete, die auf TCP basieren sind deshalb robust gegenüber Fehlern und müssen keine eigene Fehlerkorrektur bereitstellen. Aus den allgemeinen Anforderungen der Anwendung resultiert das Protokollpaket mit Header und Payload. ![]() Aufbau:
Nachdem die Struktur eines Datenpakets festgelegt wurde, kann in C# die betreffende Klasse mit dem Namen public sealed class StreamPacket : IPacket { /// <summary> /// Creates a new protocol packet, with a header section and no /// data. Some fields will be automatically set, like the protocol version. /// </summary> public StreamPacket() { ProtocolVersion = Version.PROTOCOL_VERSION; Flags = 0; Type = 0; Source = null; Destination = null; Encoding = null; Data = new byte[0]; } // ... Zu den wichtigsten Funktionen eines Pakets zählt die Serialisierung. Die Serialisierung ist eine Abbildung von Objekten auf eine externe sequenzielle Darstellungsform. Bevor das Paket über ein Netzwerk übertragen werden kann, muss es vollständig in einzelne Bytes zerlegt werden. Dazu wird eine Methode /// <summary> /// Serializes the packet and returns the packed information /// to the caller. /// </summary> /// <exception cref="System.ArgumentException">Thrown when the packet was corrupt</exception> /// <returns>The serialized packet</returns> public byte[] Serialize() { // First check if this packet is corrupt if (Corrupted) { throw new ArgumentException("StreamPacket: Trying to serialize a corrupt packet."); } // Calculate the necessary packet size byte[] buffer = new byte[HEADER_BIT_SIZE / 8 + Data.Length]; // ---------------------------------------------------- // 1. Serialize the version // ---------------------------------------------------- buffer[0] = ProtocolVersion; // ---------------------------------------------------- // 2. Serialize the flags // ---------------------------------------------------- buffer[1] = Flags; // ---------------------------------------------------- // 3. Serialize the checksum // ---------------------------------------------------- Array.Copy(BitConverter.GetBytes(Checksum), 0, buffer, 2, 2); // ---------------------------------------------------- // 4. Serialize the type // ---------------------------------------------------- Array.Copy(BitConverter.GetBytes((int)Type), 0, buffer, 4, 4); // ---------------------------------------------------- // 5. Serialize the source address // ---------------------------------------------------- Array.Copy(AddrStructureConvert.GetBytes(Source), 0, buffer, 8, 32); // ---------------------------------------------------- // 6. Serialize the destination address // ---------------------------------------------------- Array.Copy(AddrStructureConvert.GetBytes(Destination), 0, buffer, 40, 32); // ---------------------------------------------------- // 7. Serialize the size of the payload // ---------------------------------------------------- Array.Copy(BitConverter.GetBytes(Data.Length), 0, buffer, 72, 4); // ---------------------------------------------------- // 8. Serialize the data // ---------------------------------------------------- Array.Copy(Data, 0, buffer, 76, Data.Length); return buffer; } Beim Empfang eines Datenpakets muss exakt in umgekehrter Reihenfolge das Datenpaket wieder deserialisiert, also der Datenstrom in ein Objekt umgewandelt, werden. Dafür wird eine entsprechende Methode Ablauf der KommunikationDer übergeordnete Austausch der Datenpakete folgt zuvor festgelegten Kommunikationsregeln. So erwartet der Client auf Anfrage der Kontaktliste, ein Datenpaket mit der entsprechend formatierten Liste zu erhalten. Der Server muss also wissen, wie er sich zu verhalten hat, wenn er ein Datenpaket mit der betreffenden Anfrage erhält und vice versa. Nachfolgend ist ein Sequenzdiagramm abgebildet, welches einen möglichen Kommunikationsablauf illustriert. ![]() Der Ablauf muss dabei nicht streng sequentiell erfolgen. Selbstverständlich können aber vor einem Login beim Server keine Kontaktdaten abgefragt werden. |
||||||||||||||||||||||||||||||||||||||||||||
Zuletzt aktualisiert am Mittwoch, den 28. März 2012 um 18:02 Uhr |
AUSWAHLMENÜ | ||||||||
|