[C#] Communicatie tussen classes

Pagina: 1
Acties:
  • 195 views sinds 30-01-2008
  • Reageer

  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
Ik ben bezig een applicatie te maken die gebruik maakt van een connectie-class. Die connectie-class wil ik daarnaast voor andere applicaties gaan gebruiken, dus is het van belang dat het redelijk 1-richtingsverkeer wordt (i.e. ik wil niet dat de connectie class klakkeloos dingen uit de applicatie gaat aanroepen).

Echter, het is natuurlijk wel van belang dat packets die aankomen waaien in de connectie, op de één of andere manier de app. bereiken. Nu heb ik daar verschillende ideeën over, maar ik ben wel even benieuwd naar wat de experts denken (+ dat ik de oplossing die ik het mooist vond niet voor elkaar krijg).

1) Applicatie een interface laten implementen
Ik kan vereisen (en checken wat vast lelijk wordt) dat de applicatie een bepaalde interface implementeert waarin een specifieke functie bestaat die kan worden aangeroepen door de connection class als er wat binnenkomt.
Vind het zelf niet zo heel fraai, aangezien de app in mijn ogen hoger in de hierärchie staat dan de connection-class en het dus eigenlijk andersom zou moeten zijn.

2) Connection class buffert en applicatie pollt
(geen commentaar op de schrijfwijze van de werkwoorden) ;)
Dit kan natuurlijk altijd, maak een functie in de connectie die een lege string retourneert als er niks is en anders 1 pakket data. De applicatie pollt elke x seconden.
Denk beter dan optie 1, maar lijkt nog altijd niet super...

3) Applicatie geeft een delegate aan de connection
En bij het aankomen van een packet wordt door de connection layer de delegate-functie aangeroepen.
Dit is vrij flexibel volgens mij en lijkt me dus ook de mooiste methode, maar krijg ik dus niet voor elkaar (een string parameter kan ik niet zomaar in die delegate hangen, want hij verwacht een functienaam. Ook een poging er een .toString() achter te gooien hielp niet.


Ben dus even nieuwsgierig... Wat vinden jullie het mooist (en waarom) en wat kan?
In geval van optie 3, kan dit überhaupt en zo ja wat doe ik fout (indien meer info vereist, kan ik die uiteraard even geven maar voorlopig is dit tekst zat toch? ;)

Alvast thnx!

Verwijderd

Het is me niet helemaal duidelijk wat je wilt doen. Over wat voor connectie class heb je het? Is dit iets wat je zelf gaat schrijven of doel je op iets in de .NET API?

Als je de connectie class zelf gaat schrijven, dan lijkt me de mooiste oplossing om hier een public event in te maken waar de applicatie zich op kan abonneren.

  • whoami
  • Registratie: December 2000
  • Laatst online: 21-02 21:21
Optie 3 is de beste oplossing.

als je je applicatie een interface laat implementeren, dan bouw je al een afhankelijkheid in. (Een applicatie kan trouwens geen interface implementeren; een class wel. Je zou dan dus de class die je connection-class gebruikt een interface moeten laten implementeren, maar ik zou het niet doen).
Optie 2 is gewoon niet goed vind ik; het is beter dat de connectie-class laat weten als er iets aankomt, of als er iets gebeurt, en dan kom je bij optie 3 uit: gebruik maken van events.

Bij optie 3 kan je dus een eigen delegate maken, die je gebruikt als event.
Maak bv een dergelijke delegate:
code:
1
public delegate MessageEventHandler( string message );


In je class kan je dan een event maken voor dit type:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class TheClass
{
    public event MessageEventHandler MessageReceived;

    protected void OnMessageReceived( string message )
    {
         if( MessageReceived != null )
         {
             // invoke the event
             Delegate[] delegates = MessageReceived.GetInvocationList();
             foreach( Delegate del in delegates )
             {
                  ISynchronizeInvoke bliep = del.Target as ISynchronizeInvoke;

                  if( bliep != null && bliep.InvokeRequired )
                  {
                         // eventhandler moet op een andere thread uitgevoerd worden
                         bliep.Invoke (del, new object[]{message});
                  }
                  else
                  {
                         del.DynamicInvoke (new object[] {message});
                  }
             }
         }
    }
}


In je class kan je dan aangeven dat die event moet geraised worden.
code:
1
2
3
4
5
6
7
8
9
public class TheClass
{
    ....
    public void AcceptPackage( .... )
    {
        ..
        OnMessageReceived ("packet received.");
    }
}


En de class die je connection class gebruikt kan zich 'abonneren' op dat event:
code:
1
2
3
4
5
6
7
TheClass c = new TheClass();
c.MessageReceived += new MessageEventHandler (TheClass_MessageReceived);
....
public void TheClass_MessageReceived( string message )
{
   MessageBox.Show (message);
}


Zo ongeveer; let wel, alles uit de losse pols, dus er kan wel hier en daar een foutje inzitten, maar dit zou toch een idee moeten geven.

Voor de puristen: de MessageEventHandler zou eigenlijk 2 parameters moeten hebben ipv 1: nl. een object sender, en een class die afgeleid is van de EventArgs class. Die kan je dan bv MessageEventArgs noemen, en die bevat dan een member 'Message' van het type string.

Note: als je geen .NET 2.0 gebruikt, dan zal die ISynchronizeInvoke interface (zit i/d System.ComponentModel dacht ik), niet herkend worden, omdat die niet bestaat in .NET 1.x.
In dat geval zal je ipv die ISynchronizeInvoke System.Windows.Forms.Control moeten gebruiken. (Dan moet je jammergenoeg wel een reference naar de System.Windows.dll oid leggen).

[ Voor 7% gewijzigd door whoami op 13-05-2006 11:06 ]

https://fgheysels.github.io/


Verwijderd

Moet je echt expliciet alle delegates aanroepen? Ik dacht dat multicast delegates (ie. events) gewoon standaard ingebakken waren in .NET, zodat je gewoon if( MessageReceived != null ) MessageReceived("Mijn message"); kunt doen... ff checken :)

Ik heb het even zelf nagelezen in C# Unleashed en daar doen ze het inderdaad op deze eenvoudigere manier. Waar heb je jou code voorbeeld vandaan Whoami? Ik gebruik zelf al jaren de simpele manier, dus ik schrok even :P

[ Voor 35% gewijzigd door Verwijderd op 13-05-2006 11:13 . Reden: ff nagelezen ]


  • whoami
  • Registratie: December 2000
  • Laatst online: 21-02 21:21
Verwijderd schreef op zaterdag 13 mei 2006 @ 11:09:
Moet je echt expliciet alle delegates aanroepen? Ik dacht dat multicast delegates (ie. events) gewoon standaard ingebakken waren in .NET, zodat je gewoon if( MessageReceived != null ) MessageReceived("Mijn message"); kunt doen... ff checken :)
Dat kan je idd doen, maar, als je gebruik maakt van multi-threading, dan is het afaik beter om het zo te doen. Je kan nl. meerdere event-handlers hangen hebben aan die event, en sommige event-handlers moeten misschien ge-invoked worden, en andere niet; vandaar.

https://fgheysels.github.io/


Verwijderd

Dank je voor de uitleg. Dus het is in principe alleen nodig om de delegate automagisch op de GUI thread aan te roepen indien dat nodig is? Klinkt logisch, maar waarom zit dit niet standaard in de .NET events? Zou weer een hoop ellende besparen met handmatige invokes zoals het nu vaak moet :?

Ik was aan het denken aan een BackgroundWorker e.d. waar je handmatig invokes moet gebruiken om de GUI te updaten, maar da's ook weer logish, want de BackgroundWorker DoWork event will je natuurlijk niet op je GUI thread hebben draaien. Zou het hele principe een beetje overbodig maken :+

Tijd voor een kopje koffie :)

[ Voor 39% gewijzigd door Verwijderd op 13-05-2006 11:28 . Reden: Nog niet helemaal wakker ]


  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
Ontzettend bedankt, ik ga eens knutselen.
Goed te zien dat er wat discussie ontstaat, blijbkaar geen triviale vraag. ;)

Ik laat wel even horen als het gelukt is (en anders ook) :P

Ik doe het overigens in .NET 2003 en ik ga die connection class zelf maken.

  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
Met wat bloed, zweet en tranen heb ik dit erin gekregen! :)
Ontzettend bedankt dus. :D

Ik heb alleen nog een andere vraag die ik via Google niet zo vlug beantwoord zag.
Het doel van het geheel is in eerste instantie om een x aantal figuren via 1 host te laten connecten.
Dit heb ik in VB al een keer gedaan d.m.v. WinSockets, maar daar zaten nogal wat haken en ogen aan...
Toen ik met C# een standaard TCP functionaliteit zag, werd ik al vrij blij en ik dacht... Die gaan we misbruiken. :P

Alleen als ik het internet afstruin, zie ik allemaal voorbeelden van een function die een connectie opzet, wat data stuurt en weer afsluit... Dat schiet dus niet op, ik wil hem in stand houden en zodra er data binnenkomt, die afhandelen.

Nu kon ik daarnaast op Internet niks vinden over deze manier van werken... Dus (stomme vraag misschien): was deze functionaliteit WinSock only en moet ik daar nu dus ook weer voor gaan, of zoek / denk ik gewoon verkeerd?

  • MTWZZ
  • Registratie: Mei 2000
  • Laatst online: 13-08-2021

MTWZZ

One life, live it!

Wat je kunt doen is een aparte thread maken die de socket in de gaten houdt via Socket.Poll() en op basis daarvan de afhandeling doen

Nu met Land Rover Series 3 en Defender 90


  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
MTWZZ schreef op zondag 14 mei 2006 @ 20:36:
Wat je kunt doen is een aparte thread maken die de socket in de gaten houdt via Socket.Poll() en op basis daarvan de afhandeling doen
Hmmmmmm, idd.
Idee was alleen dat ik zonder timers wilde werken en daar zit ik als ik de socket moet pollen dan weer aan vast, of niet?

Is WinSock dan geen beter alternatief?

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23:27
BratMokstrof schreef op zondag 14 mei 2006 @ 20:30:
Nu kon ik daarnaast op Internet niks vinden over deze manier van werken... Dus (stomme vraag misschien): was deze functionaliteit WinSock only en moet ik daar nu dus ook weer voor gaan, of zoek / denk ik gewoon verkeerd?
Welke manier van werken bedoel je? Je hebt een connection class die een verbinding op zet en een event gooit zodra er iets binnenkomt ... deze verbinding kun je toch openhouden zolang je em nodig hebt ?

(NB Op het moment dat er een netwerkfout optreedt kun je het beste je verbinding opnieuw opbouwen )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
Het is idd. de bedoeling het open te houden.
Punt is alleen dat ik onder VB gewend was dat er een bepaald event (of hoe dat daar heet) werd gevuurd op het moment dat er een packet binnenkwam.

Ik vraag me af hoe dat hier is, moet ik iets schrijven als:
C#:
1
2
3
4
5
6
7
while (true)
{
    if (socket.Poll)
    {
        dataReceived(...);
    }
}


En dat vind ik niet zo mooi (weet ook niet waarom). Ziet er inefficient uit. De vraag is dan dus ook eigenlijk: is er geen mogelijkheid dat ik op een event van data-reival abboneer zodat ik kan reageren als er data is, zonder zelf in de gaten te moeten houden of het er is?

Verwijderd

Je hebt natuurlijk de asynchrone functies op een socket nog. Kijk eens naar BeginReceive enzo.

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23:27
BratMokstrof schreef op maandag 15 mei 2006 @ 12:56:
Het is idd. de bedoeling het open te houden.
Punt is alleen dat ik onder VB gewend was dat er een bepaald event (of hoe dat daar heet) werd gevuurd op het moment dat er een packet binnenkwam.

Ik vraag me af hoe dat hier is, moet ik iets schrijven als:
C#:
1
2
3
4
5
6
7
while (true)
{
    if (socket.Poll)
    {
        dataReceived(...);
    }
}

En dat vind ik niet zo mooi (weet ook niet waarom). Ziet er inefficient uit. De vraag is dan dus ook eigenlijk: is er geen mogelijkheid dat ik op een event van data-reival abboneer zodat ik kan reageren als er data is, zonder zelf in de gaten te moeten houden of het er is?
Achso, ik was in de veronderstelling dat die connection class al een event afvuurde zodra er data binnenkomt. ( Daar zul je met die asynchrone socketfunctions ook je delegates moeten aanroepen denk ik )

BTW, gevoelsmatig zou ik ook zeggen dat het inefficient is, maar ik denk dat dat meevalt als het onderwater met events oid is gebouwd. Het enige is dat je een loop in je programma moet hebben die die poll doet. ( Kan je hoofdlus zijn of een aparte thread, maar dat vereist wel een bepaalde opbouw van je applicatie )

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
farlane schreef op maandag 15 mei 2006 @ 16:39:BTW, gevoelsmatig zou ik ook zeggen dat het inefficient is, maar ik denk dat dat meevalt als het onderwater met events oid is gebouwd. Het enige is dat je een loop in je programma moet hebben die die poll doet. ( Kan je hoofdlus zijn of een aparte thread, maar dat vereist wel een bepaalde opbouw van je applicatie )
Ik heb juist het idee dat het helemaal niet inefficient is (maarja, ik ben nou niet direct de kenner ofzo). :)
En dat polls worden voorkomen op deze manier.

1) Event in ConnectionClass (d.m.v. asynchrone dingen) dat wordt gevuurd als er data binnenkomt.
2) Vervolgens wordt een event aangeroepen uit de applicatieclass, en op die manier krijgt de applicatie de data...

Lijkt me juist dat er dan geen loopjes of wat ook nodig zijn, of zie ik het nou verkeerd?
(Deel 2 heb ik overigens werkend, deel 1 moet ik nog eens naar gaan kijken, maar tijd ontbrak nog even).

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23:27
Volgens mij bedoelen we hetzelfde. Mijn verhaal over efficientie ( of lack thereof ) van je poll loop voorbeeld, niet over je eventgebaseeerde constructie :)

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
farlane schreef op dinsdag 16 mei 2006 @ 08:54:
Volgens mij bedoelen we hetzelfde. Mijn verhaal over efficientie ( of lack thereof ) van je poll loop voorbeeld, niet over je eventgebaseeerde constructie :)
Ah, pardon, miscommunicatie. :)

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21-02 03:42
BratMokstrof schreef op maandag 15 mei 2006 @ 12:56:
Ik vraag me af hoe dat hier is, moet ik iets schrijven als:
C#:
1
2
3
4
5
6
7
while (true)
{
    if (socket.Poll)
    {
        dataReceived(...);
    }
}


En dat vind ik niet zo mooi (weet ook niet waarom). Ziet er inefficient uit. De vraag is dan dus ook eigenlijk: is er geen mogelijkheid dat ik op een event van data-reival abboneer zodat ik kan reageren als er data is, zonder zelf in de gaten te moeten houden of het er is?
Zo pollen moet je inderdaad niet doen. Die sockets ondersteunen verder ook geen notifications voor zover ik in de MSDN zie (in tegenstelling tot sockets in de Windows API). De gebruikelijke methode hiervoor is ofwel per verbinding een aparte thread starten waarin je simpelweg data leest als die beschikbaar is, of als je veel verbindingen hebt, een enkele thread waarin je met Socket.Select() de sockets selecteert waaruit wat te lezen valt.

Beide oplossingen zijn blocking, maar dat geeft niet als ze in een aparte thread plaatsvinden.

Verwijderd

Ik zal mezelf nog maar eens quoten, naar aanleiding van soultaker's post:
Verwijderd schreef op maandag 15 mei 2006 @ 14:01:
Je hebt natuurlijk de asynchrone functies op een socket nog. Kijk eens naar BeginReceive enzo.
code:
1
2
3
4
5
6
7
8
public IAsyncResult BeginReceive(
   byte[] buffer,
   int offset,
   int size,
   SocketFlags socketFlags,
   AsyncCallback callback,
   object state
);


Aan deze functie geef je een callback mee, en daarin kan je je main thread notifyen of de data direct afhandelen of iets anders doen, maar net wat je wilt.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 21-02 03:42
Ah, dat kan inderdaad ook.

  • BratMokstrof
  • Registratie: Mei 2003
  • Laatst online: 10-02 08:54
Ik heb beetje gekeken naar die callback, het is me nog niet helemaal duidelijk, maar tijd om ermee te gaan prutsen ontbreekt (helaas) even. :(

Zodra ik iets heb (vraag of succesverhaal), laat ik het wel even weten. :)

Tot zover thnx voor alle hulp!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 23:27
Soultaker schreef op dinsdag 16 mei 2006 @ 13:32:
Zo pollen moet je inderdaad niet doen.
De lus is een beetje krap op deze manier B) maar ik zie hier een 'doodnormale' select call waar op zich niets mis mee is.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1