Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[C#] XML Serialized object versturen via TcpClient

Pagina: 1
Acties:

  • cixx
  • Registratie: Augustus 2005
  • Laatst online: 28-09-2024
Hallo, ik heb een probleem met het versturen van een serialized object via een TcpClient.

Het versturen gaat goed, alleen kan de ontvanger het succesvol ontvangen als de sender de verbinding direct na het versturen van het object sluit. De uitleg is een beetje krom dus ik zal een code voorbeeld geven:

Client:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, 1987);

// Create streams.
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream);
StreamReader reader = new StreamReader(stream);
writer.AutoFlush = true;

// Serialize object and send it.
XmlSerializer sr = new XmlSerializer(typeof(Game));
sr.Serialize(writer, _game);

//Hier hangt het handeltje als ik de code zo laat, als ik echter hier 'client.Close()' neerzet dan ontvangt de server het wel goed.


Server:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Listen for client.
TcpListener _tcpListener = new TcpListener(IPAddress.Loopback, 1987);
_tcpListener.Start();
TcpClient client = _tcpListener.AcceptTcpClient();

// Create streams.
NetworkStream ns = client.GetStream();
StreamReader reader = new StreamReader(ns);
StreamWriter writer = new StreamWriter(ns);
XmlSerializer sr = new XmlSerializer(typeof(Game));

// Deserialize object
Game newGame = (Game)sr.Deserialize(reader);

// Na bovenstaande regel gaat het niet verder tenzij de sender de verbinding verbreekt.


Ik heb het idee dat ik voor of na het sturen van het object nog iets moet doen waardoor de ontvanger weet dat het versturen voltooid is. Ik heb alleen geen idee wat dat precies moet zijn.

Het is geen optie om de connectie te sluiten en daarna een nieuwe aan te maken, de verbinding moet bruikbaar blijven na het versturen/ontvangen van het object.

Ik hoop dat jullie mij verder kunnen helpen.

  • whoami
  • Registratie: December 2000
  • Laatst online: 13:47
Flush eens nadat je het object verstuurd hebt ?

Alhoewel, je AutoFlush staat wel op true ....

[ Voor 34% gewijzigd door whoami op 28-06-2008 16:11 ]

https://fgheysels.github.io/


  • cixx
  • Registratie: Augustus 2005
  • Laatst online: 28-09-2024
Handmatig flushen werkt helaas ook niet.

  • eek
  • Registratie: Februari 2001
  • Laatst online: 06-04-2020

eek

@MagickNET

Misschien alleen stream.close() doen? Of ben je dan ook je verbinding kwijt?

Skill is when luck becomes a habit.


  • Haan
  • Registratie: Februari 2004
  • Laatst online: 17-11 08:45

Haan

dotnetter

eek schreef op zaterdag 28 juni 2008 @ 19:52:
Misschien alleen stream.close() doen? Of ben je dan ook je verbinding kwijt?
Dat lijkt mij ook een goede, maar dan niet de NetworkStream sluiten, maar de StreamWriter.

Kater? Eerst water, de rest komt later


  • cixx
  • Registratie: Augustus 2005
  • Laatst online: 28-09-2024
Als je de StreamWriter eenmaal sluit kan je de stream nooit nog eens gebruiken om op te schrijven, ook niet als je een hele nieuwe StreamWriter maakt.

Ik heb inmiddels een andere oplossing bedacht.

Omdat ik hem naar XML serialize kan ik ook gewoon de XML data via een gewone string versturen.
Via de Create methode van de XmlWriter schrijf ik de XML data in een stringbuilder. Aan de kant van de server deserialize ik de data weer doormiddel van een XmlReader.

C#:
1
2
3
4
5
6
7
8
// Sender
StringBuilder stringBuilder = new StringBuilder();
sr.Serialize(XmlWriter.Create(stringBuilder), myObject);
writer.WriteLine(stringBuilder.ToString());

//Reciever
string input = reader.ReadLine();
MyObject myObject = (MyObject)sr.Deserialize(XmlReader.Create(input));


Het is iets minder mooi, maar het werkt wel.

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 17-10 16:43
Ik heb zelf even naar je code gekeken en er mee gestoeid.

Wat fout lijkt te gaan is dat zodra de server het serializable object weer opbouwt hij niet meer terugspringt naar de methode waar hij daarvoor inzat.

iig kwam ik met breakpoints en steptrough niet meer uit bij de volgende regel, maar stopte het programma (omdat het verder niets was) in de contructor van het te de-serialize object.

Hoe meer ik ernaar kijk hoe vreemder het wordt, het kan toch niet dat de deserializer de hele stack breekt?

EDIT:

Ok fixed, je kunt voor networkstreams geen XMLSerializer gebruiken omdat deze blocked en daarom pas stopt met lezen als je de stream sluit. De oplossing om meerdere objecten / gegevens te versturen was even knutselen. Het beste is een BinaryFormatter ( using System.Runtime.Serialization.Formatters.Binary; )

Op deze manier krijg je de volgende 2 classen (even snel gemaakt dus niet al te netjes). Zo kun je asynchroon wachten totdat een client connect, en op dat moment data oversturen en ontvangen zonder dat er iets blocked en zo kun je ook meerdere gegevens oversturen.

SObject is trouwens een even snel gemaakt serialisable object (vergeet niet [Serializable] bij de class declaratie te zetten) met 1 public string "helloworld".

-De Client class
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Client
    {
        private SObject _game;

        public Client(SObject _game)
        {
            this._game = _game;
        }

        public void Send()
        {
            TcpClient client = new TcpClient();
            client.Connect(IPAddress.Loopback, 2008);
            NetworkStream stream = client.GetStream();            
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(stream, _game);
        }
    }


-De Server class
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Server
    {        
        public Server()
        {
            TcpListener listener = new TcpListener(IPAddress.Loopback, 2008);
            listener.Start();
            listener.BeginAcceptSocket(new AsyncCallback(AcceptClient), listener);
        }

        private void AcceptClient(IAsyncResult callback)
        {            
            TcpListener listener = (TcpListener)callback.AsyncState;
            Socket clientSocket = listener.EndAcceptSocket(callback);
            NetworkStream networkStream = new NetworkStream(clientSocket);           
            BinaryFormatter bf = new BinaryFormatter();            
            SObject newSObject = (SObject)bf.Deserialize(networkStream);
            //Doe nog iets leuks zoals de string printen
            Console.Out.WriteLine(newSObject.helloWorld);            
        }
    }

[ Voor 80% gewijzigd door roy-t op 30-06-2008 00:16 ]

~ Mijn prog blog!


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Het probleem is dat je server niet 'weet' wanneer er geen data meer over de connectie komt. En Deserialize is eigenlijk een soort 'blocking' methode. Pas als *alle* data binnen is, gaat Deserialize verder. Alleen is een netwerk verbinding in principe een oneindige string van data.

De .NET serializers bevatten niet de inteligentie om te 'zien' dat bijvoorbeeld een serialized block al volledig binnen is, terwijl inmiddels een tweede wordt verstuurd. HTTP gebruikt om die reden de 'lege' regel om aan te geven dat een request voltooid is.

De meest eenvoudige oplossing is om je serialized block naar een byte array te schrijven. Vervolgens gebruik je de eerste 4 bytes om de lengte (byte[].Length) van het bericht aan te geven en daarachter verzend je de array. Hetzelfde doe je ook aan de server. Je leest de eerste 4 bytes, en vervolgens lees je van de netwerk stream het aangegeven aantal bytes.

If it isn't broken, fix it until it is..


  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 17-10 16:43
Niemand_Anders schreef op maandag 30 juni 2008 @ 09:01:
De .NET serializers bevatten niet de inteligentie om te 'zien' dat bijvoorbeeld een serialized block al volledig binnen is, terwijl inmiddels een tweede wordt verstuurd.
*Psst, kijk is een post omhoog de BinaryFormatter is een onderdeel van de .Net System.Runtime.Serialization namespace en heeft deze eigenschappen wel, ook heb ik net precies verteld wat jij zegt over de XMLSerializer :P.

~ Mijn prog blog!

Pagina: 1