Benutzer mit den meisten Antworten
Wie sende/empfange ich eine Datenstruktur per tcpclient/Networkstream?

Frage
-
Hallo, ich habe mal wieder ein grundsätzliches Problem - stehe das erste Mal vor dieser Aufgabe.
Ich möchte eine Datenstruktur über das Netzwerk (TcpClient) versenden und auf den anderen Seite empfangen.
Hier die Struktur und ein Prinzip-Beispielprogramm:Module Test Dim DOCCM_IP As String = "127.0.0.1" Dim DOCCM_Port As Integer = 50000 Structure stDOCCMAgent Dim UID As String Dim Firma As enFirma Dim Clan As String Dim Name As String Dim Level As Integer Dim Pos As stZiel End Structure Structure stDOCCMShips Dim UID As String Dim Clan As String Dim Name As String Dim Firma As enFirma Dim XPos, YPos As Integer Dim LastUpdate As Date End Structure Structure stDOCCMGate Dim Art As enGateArt 'Aussehen des Gates Dim Name As String 'Name eines Gates Dim X As Integer 'X-Position des Gates Dim Y As Integer 'Y-Position des Gates End Structure Structure stDOCCMStation 'Dates einer Station Dim Art As enGateArt 'Aussehen der Station Dim Name As String 'Name einer Station Dim X As Integer 'X-Position der Station Dim Y As Integer 'Y-Position der Station End Structure Structure stDOCCMMap Dim Name As String Dim Gates As List(Of stDOCCMGate) Dim Stations As List(Of stDOCCMStation) End Structure Structure stDOCCM Dim Map As stDOCCMMap Dim Agent As stDOCCMAgent Dim Ships As Dictionary(Of String, stDOCCMShips) End Structure Dim DOCCM As stDOCCM Sub Test DOCCM.Map.Gates = New List(Of stDOCCMGate) DOCCM.Map.Stations = New List(Of stDOCCMStation) DOCCM.Ships = New Dictionary(Of String, stDOCCMShips) DOCCMtcpClient = New TcpClient() DOCCMtcpClient.Connect(DOCCM_IP, DOCCM_Port) DOCCMNetworkStream = DOCCMtcpClient.GetStream() Dim sendBytes As [Byte]() Do 'Fülle DOCCM mit Daten .... With DOCCM .Map.Name = DOD.MapName .Map.Gates.Clear() .Map.Stations.Clear() .Ships.Clear() For Each Gate In Map.Gates If Left(Gate, 1) = "P" Then 'Gate Dim GT As stDOCCMGate = Nothing Dim GateNr As Integer = CInt(Strings.Right(Gate, Gate.Length - 1)) 'GateNummer GT.Art = Gates(GateNr).Art GT.Name = Gates(GateNr).Name GT.X = Gates(GateNr).X GT.Y = Gates(GateNr).Y .Map.Gates.Add(GT) Else Dim StationNr As Integer = CInt(Strings.Right(Gate, Gate.Length - 1)) 'StationsNummer Dim ST As stDOCCMStation = Nothing ST.Art = Stationen(StationNr).Art ST.Name = Stationen(StationNr).Name ST.X = Stationen(StationNr).X ST.Y = Stationen(StationNr).Y .Map.Stations.Add(ST) End If Next With .Agent .UID = Account.UID .Clan = DOD.OwnShip.Clan .Firma = DOD.OwnShip.Firma .Level = DOD.OwnShip.Level .Name = DOD.OwnShip.Name .Pos.X = DOD.OwnShip.XPos .Pos.Y = DOD.OwnShip.YPos End With If ForeignShips.Count > 0 Then For Each FS In ForeignShips.Values Dim Ship As stDOCCMShips = Nothing Ship.UID = FS.UID Ship.Clan = FS.Clan Ship.Firma = CType(FS.Firma, enFirma) Ship.LastUpdate = FS.LastUpdate Ship.Name = FS.Name Ship.XPos = FS.XPos Ship.YPos = FS.YPos .Ships.Add(FS.UID, Ship) Next End If End With sendBytes = ?????? 'Hier müsste DOCCM in ein Byte-Array convertiert werden NetworkStream.Write(sendBytes, 0, sendBytes.Length) Loop While DatenVorhanden DOCCMNetworkStream.Dispose() DOCCMtcpClient.Close() End Sub End Module
Ich befürchte, das das nicht so einfach geht wie ich gehofft habe. Welche Möglichkeiten habe ich?
Bisher habe ich in eigenen Client/Server-Anwendungen immer nur Zeicheketten versendet/empfangen.
Muss ich meine DOCCM-Struktur nun auch in ihre Elemente zerlegen und in geeigneter Form als Zeichenketten versenden?
Antworten
-
Hallo,
das beste wäre Du wandelst Deine Strukturen für den Transfer in Xml-Daten um,
zum Beispiel via XmlSerializer (siehe dort auch Weitere Ressourcen am Ende).
Denn beim Transferieren von Daten übers Internet kommt bei binären Formaten
die Byte-Order zum Tragen und sobald Du mit unterschiedlichen Hosts kommunizieren willst,
gibt es schnell Datensalat.
Für eine binäre Übertragung müßtest Du z. B. die Integer durch den BitConverter konvertieren,
denn Standard für IP-Übertragungen ist Big Endian - wohingegen auf x86 Rechner LittleEndian verwendet wird.
Hinzukommt dass Du die Zeichenkodierung bei Zeichenketten festlegen mußt (Unicode/Utf-8).
Nur wenn es ein interner Transfer ist, könntest Du die binäre Serializierung verwenden,
wobei Du aber auch dort mehr Vorkehrungen für spätere Änderungen treffen mußt.
Insgesamt wird das sehr aufwändig, wohingegen der Weg über Xml Dir ein definiertes Zeichen-Format
vorgibt, was Du über XmlDocument etc. beiderseitig über vorhandene .NET Klassen verarbeiten kannst.
Wenn Du zudem ein XmlSchema definierst bist Du für spätere Erweiterungen gerüstet.
Gruß Elmar- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 24. Februar 2010 10:06
Alle Antworten
-
Hallo,
das beste wäre Du wandelst Deine Strukturen für den Transfer in Xml-Daten um,
zum Beispiel via XmlSerializer (siehe dort auch Weitere Ressourcen am Ende).
Denn beim Transferieren von Daten übers Internet kommt bei binären Formaten
die Byte-Order zum Tragen und sobald Du mit unterschiedlichen Hosts kommunizieren willst,
gibt es schnell Datensalat.
Für eine binäre Übertragung müßtest Du z. B. die Integer durch den BitConverter konvertieren,
denn Standard für IP-Übertragungen ist Big Endian - wohingegen auf x86 Rechner LittleEndian verwendet wird.
Hinzukommt dass Du die Zeichenkodierung bei Zeichenketten festlegen mußt (Unicode/Utf-8).
Nur wenn es ein interner Transfer ist, könntest Du die binäre Serializierung verwenden,
wobei Du aber auch dort mehr Vorkehrungen für spätere Änderungen treffen mußt.
Insgesamt wird das sehr aufwändig, wohingegen der Weg über Xml Dir ein definiertes Zeichen-Format
vorgibt, was Du über XmlDocument etc. beiderseitig über vorhandene .NET Klassen verarbeiten kannst.
Wenn Du zudem ein XmlSchema definierst bist Du für spätere Erweiterungen gerüstet.
Gruß Elmar- Als Antwort markiert Robert BreitenhoferModerator Mittwoch, 24. Februar 2010 10:06
-
Danke für deine Antwort.
An etwas wie die BinaryFormatter-Klasse hatte ich gedacht. Und die Beispiel dort sind auch sehr übersichtlich gehalten.
Sender und Empfänger sind immer Programme, die von mir geschrieben sind. Es sind beides VB-Net-Programme.
Kann es zu Schwierigkeiten kommen, wenn ein Programm auf einem anderen Rechner läuft, auf dem ein 64-Bit Windows installiert ist (ich nutze ein 32Bit-Windows) - ich denke da z.b. an die evtl. unterschiedlichen Wortbreite für den Typ Integer, oder ist der unter .Net immer 32-Bit breit? Und wenn es da Probleme geben könnte, dann ich VB.Net (ich habe die Express-Version) zwingen den Code auf dem Zielsystem (in dem Fall 64-Bit) als 32-Bit-Anwendung auszuführen? Ich meine da mal etwas entsprechendes gelesen zu haben.
Gruß Valerie
PS.
Ich mag den XML-"Quatsch" nicht und brauche das sonst auch niemals .... ;) -
Hallo Valerie,
die .NET/CLR Datentypen sind unabhängig vom Betriebssystem,
so ist Integer ist immer ein 32-Bit Integer (System.Int32).
Was den Xml-Quatsch angeht:
Das wirst Du spätestens schätzen lernen, wenn Du mal Fehler suchen mußt,
denn das Xml kann man so noch lesen.
Und willst Du es einfach haben, kannst Du Linq To Xml
wo Du Xml Code direkt in Visual Basic einbetten kannst.
Bei einem BinaryFormatter wiederum mußt Du immer dafür sorgen,
dass auf beiden Enden identische (signierte) Assemblies verwendet werden.
Sonst ist das schnell vorbei mit einfach.
Gruß Elmar -
... identische (signierte) Assemblies ...
Was meinst du genau damit? Meinst du das die Quell- und die Empfangsdatenstruktur identische sein muss - wenn ja, das ist ja selbstverständlich das die Identisch sein müssen.
Was das nachlesen angeht, ich gehöre der Generation an, die per Packetsniffer auch noch gut binäre Daten "mitlesen" kann.
Gruß,Valerie
PS.
Ich komme aus der 80er-Jahre Assembler-Hacker-Szene, kannte den Atari 800XL (zum Teile auch den C64) bis ins letzte Bit.
-
Hallo Valerie,
schau Dir den Link zur binären Serialisierung an, den ich schon gepostet habe -
da steht so ziemlich alles was man wissen muß, insbes. auch
Versionstolerante Serialisierung
Gruß Elmar
P.S.: Ich bin auch ziemlich lange im Geschäft und habe
schon Atari, Z80, C64 am liebsten mit Assembler gequält.
P. P. S:
Und ich habe bis heute versucht der Entwicklung einigemaßen
hinterher zu stolpern. Und Xml gehört IMHO zu den Dingen.
mit den sich ein Entwickler auskennen sollte.
-
Hallo Elmar,
ich habe das mit dem BinaryFormatter mal probiert und habe nun gesehen, zu welchen Problemen es da kommt.
Nicht das ich das alle vollständig verstehen würde, aber BinaryFormatter scheint nicht dafür gemacht zu sein Daten zwischen unterschiedlichen Programmen auszutauschen, auch wenn die Datenstruktur die ausgetaischt werden soll, im Quell- und Zielprogramm identisch sind. Die Daten kommen zwar beim Ziel-Programm an, aber dort wird ein passendes Assembly vermisst ("Die Assembly "DOBBC2s, Version=2.3.3.1, Culture=neutral, PublicKeyToken=null" kann nicht gefunden werden.").
Naja, die Serialisierung ist wohl fast ausschließlich dazu gemacht, (Objekt-)Zustände eines Programms festzuhalten, schade das man damit nicht mehr machen kann, das wäre so bequem.
Ok, also werde ich mal eine anderen Ansatz probieren... - nein, kein XML, das ist mir zu sperrig und die Daten sind dann viel gut gut lesbar, so das ich die auch noch verschlüsseln müsste.
Aber vielleicht, wenn der nächsten Ansatz nicht funktioniert, werde ich mich doch mal mit XML beschäftigen.
Hier noch die Code-Schnipsel meines Versuches:
'Auf der Senderseite Dim formatter As New BinaryFormatter formatter.Serialize(DOCCMNetworkStream, DOCCM) 'Auf der Empfängerseite Dim formatter As New BinaryFormatter DOCCM = DirectCast(formatter.Deserialize(DOCCMNetworkStream), stDOCCM)
Gruß, Valerie
PS.
Ich habe mich ja zumindest lesend schon mit XML beschäftigt - ich rufte damals XML-Daten von einem Web-Server ab und verarbeitete die Daten - und fand das ganze sehr grauselig und sperrig. Ic habe die Routine dann umgeschrieben und die XML-Daten per String-Verarbeitung verarbeitet, was mir ehrheblich leichter gefallen ist und ich dort, nach meinem empfinden schnelle und direkter zum Ziel gekommen bin.
Nenn' es Macke oder Aversion ...
-
Hallo Valerie,
mit der Fehlermeldung bist Du genau darauf gestossen,
was das von Dir extrahierte Statement besagen sollte:
Wenn Du die Assembly mit den Klassen veränderst
mußt Du sie auch beim Empfänger installieren.
Denn die Informationen über die Assembly steht mit
in der binären Serialisierung.
Deswegen sind solche Klassen in einer eigenen Schnittstellen
Assembly am besten aufgehoben. Und man sollte kein
automatisches Hochzählen für AssemblyVersion verwenden,
da damit bei jedem Kompilerlauf sich die Assembly - Signatur verändert.
Zur Xml Serialisierung:
Der Code wird am Ende nicht aufwändiger. Siehe z. B.:
http://dzaebel.net/XmlSerializer.htm
(und das ist nicht mal sonderlich toll gemacht)
Du solltest Dich nicht zu früh von Aversionen leiten lassen.
Denn gerade .NET hat sehr viel Unterstützung eingebaut -
auch wegen der mittlerweile abgeflachten Hype seitens Microsoft,
die ich nicht unbedingt geteilt habe ;-)
So hätte man von Dir angesprochenen WebService
nicht mehr von Hand verarbeiten müssen.
Lies Dir die Abschnitte mal zu beiden Bereichen so vorurteilsfrei
wie möglich durch.
Gibt es dann Fragen zu einzelnen Abschnitten stelle sie hier.
Gruß Elmar