Laden...

Remoting .net <-> Mono

Erstellt von Rumpel vor 16 Jahren Letzter Beitrag vor 16 Jahren 1.796 Views
Rumpel Themenstarter:in
40 Beiträge seit 2007
vor 16 Jahren
Remoting .net <-> Mono

Hallo!

Ich hab hier ein Remoting-Problem, dass ich einfach nicht zu lösen bekomme.

Und zwar baue ich eine Verbindung von einem Windows .net-Client zu einem Linux Mono-Server auf. Funktioniert soweit wunderbar, das serverseitige WellKnownObject bekomme ich auch, alle Funktionen klappen prima.

Übergebe ich jedoch dem Serverobject ein Client-Object (mbr) und möchte dann eine Methode ausführen, steht der Client.
Unter .net, wenn ich beide Komponenten lokal laufen lasse funktioniert das Prima, genauso unter Mono.
Nur die Richtung mono->.net scheint nicht ganz zu klappen.

Ich habe inzwischen alles Mögliche probiert, egal wie es mache, methoden, Felder, Events, Sobald ich auf dem Server eine Client-Object-Methode ausführe bleibt irgendwo der Thread stehen. Auf dem Server aber scheint alles normal weiter zu arbeiten.

Das einzige was funktioniert hat war, wenn ich auf dem Client auch ein RegisterwellKnownObject gemacht habe, das ich dann auf dem Server instanziere. Nur ist das Firewalltechnisch und wegen dem nötigen Portforwarding auf dem Router keine wirkliche Alternative, abgesehen davon, dass ich dann die Client-IP brauche.

Kennt vielleicht jemand das Problem und hat eine Lösung? Ich finde einfach nichts dazu...

Gruß, Rumpel

3.728 Beiträge seit 2005
vor 16 Jahren
Kanäle

Was für Kanäle verwendest Du?

Wenn Du vom Server aus auch von MarshalByRef abgeleitete Client-Objekte aufrufen willst, darfst Du nicht TcpServerChannel und TcpClientChannel verwenden, sondern musst bei Client und Server TcpChannel verwenden. Der Port des Client-Kanals sollte auf 0 gesetzt sein (Damit wählt der Client automatisch einen freien Port).

Rumpel Themenstarter:in
40 Beiträge seit 2007
vor 16 Jahren

Ich habe beide Seiten als TcpChannel eingerichtet. Hier der Source mit dem ich das Problem getestet und zu umgehen probiert habe:

Der Client:

            
BinaryServerFormatterSinkProvider bsfsp = new System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider();
bsfsp.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 0;

IChannel hc = new TcpChannel(props, null, bsfsp);
ChannelServices.RegisterChannel(hc,false);

remoteObject r = (remoteObject)Activator.GetObject(typeof(remoteObject), "tcp://localhost:4321/remoteObject1");
TestClass t = new TestClass();
 r.Test(t);

Eine gemeinsame Assembly:

    public class remoteObject : MarshalByRefObject
    {
        public void Test(TestClass c)
        {
            c.test();
        }
    }

    public class TestClass : MarshalByRefObject
    {
        public void test()
        {
            Console.WriteLine("Test");
        }
    }

Der Server:

           
BinaryServerFormatterSinkProvider bsfsp = new System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider();
bsfsp.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 4321;

IChannel hc = new TcpChannel(props, null, bsfsp);
ChannelServices.RegisterChannel(hc);
            
RemotingConfiguration.RegisterWellKnownServiceType(typeof(remoteObject), "remoteObject1", WellKnownObjectMode.Singleton);            

Funktioniert auch lokal, nur wenn der Serverteil auf meinem Linux-Server läuft funktioniert das nicht mehr - der Client wartet dann immer das der Befehl r.Test(t) zurückkehrt und bleibt dort stehen. Der Server läuft derweil normal weiter und weitere Clients werden normal bedient.

3.728 Beiträge seit 2005
vor 16 Jahren
Assembly

Pack die TestClass mal in eine separate Assembly und versehe beide Klassen mit Schnittstellen, die wiederum in separaten Assemblies liegen. Versuch dann mal jeweils auf der Client-Seite (Der Server ist der Client von TestClass) nur mit den Schnittstellen zu arbeiten.

Damit wird jeweils auf dem Client nicht die Implementierung benötigt.

Rumpel Themenstarter:in
40 Beiträge seit 2007
vor 16 Jahren

Auf dem Client brauch ich zumindest die Implementierung von TestClass - muss ja eine Instanz erzeugen. Hab dafür auf dem Server das entsprechende Interface verwendet.

Das Ergebnis ist das Selbe. Diesmal war ich ein wenig geduldiger, nach ca. 3 Minuten kommt eine Exception "Network Subsystem is down".

Vielleicht kann jemand mit dem Stacktrace was anfangen:


System.Runtime.Remoting.RemotingException wurde nicht behandelt.
  Message="Network subsystem is down"
  Source="System.Runtime.Remoting"
  StackTrace:
    Server stack trace: 
      at System.Runtime.Remoting.Channels.Tcp.HostConnectionPool.CreateConnection () [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.HostConnectionPool.GetConnection () [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.TcpConnectionPool.GetConnection (System.String host, Int32 port) [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream) [0x00000] 
      at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg) [0x00000] 
    Exception rethrown at [0]: 
      at System.Runtime.Remoting.Channels.Tcp.HostConnectionPool.CreateConnection () [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.HostConnectionPool.GetConnection () [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.TcpConnectionPool.GetConnection (System.String host, Int32 port) [0x00000] 
      at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.ProcessMessage (IMessage msg, ITransportHeaders requestHeaders, System.IO.Stream requestStream, ITransportHeaders& responseHeaders, System.IO.Stream& responseStream) [0x00000] 
      at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage (IMessage msg) [0x00000] 
    Exception rethrown at [1]: 
       bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       bei IremoteObject.Iremoteobject.Test(ItestClass t)
       bei Testclient.client.Main(String[] args) in C:\Dokumente und Einstellungen\Entwicklung\Eigene Dateien\Visual Studio 2005\Projects\Testclient\Testclient\client.cs:Zeile 30.
       bei System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
       bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bei System.Threading.ThreadHelper.ThreadStart()

🤔 Leider finde ich beim Googeln auch keine Hinweise... Versuchsweise mal alle Firewalls/Virenkiller usw. deaktiviert, auch vom Router und Alle Ports zum Rechner weitergeleitet. Keine Besserung. morgen habe ich einen Laptop zu Verfügung, auf dem werd ichs auch nochmal testen, obs vielleicht an meinem Rechner liegt, und eventuell komm ich noch über einen komplett anderen Standort zu Testen. Und ich werde schauen dass ich die aktuellsten Mono-Versionen auftreibe (Momentan Debian-Stable 1.2.2)

Ich bin normalerweise echt zäh und Suche mir meine Infos im Internet zusammen, aber hier werf ich bald das Handtuch...

3.728 Beiträge seit 2005
vor 16 Jahren
Client

Am Client die Implementierung von TestClass, aber am Server nur das Interface. Implementierung und Schnittstelle in separaten Assemblies. Hast Du das genau so probiert?

Mit welchem Compiler hat Du die TestClass-Assembly kompiliert? Mono oder .NET?

Läuft der Server auf Windows 2000? Da gibt es nämlich einen Bug:
http://bugzilla.ximian.com/show_bug.cgi?id=74081

Wenn alles nichts hilft, könntes Du einen Bug melden oder einfach eine E-Mail an das mono-Team schicken.
http://www.mono-project.com/Contact
http://www.mono-project.com/Bugs

Bis der Bug gefixt ist (wenn es wirklich ein Bug ist), kannst Du Dir auch vielleicht mit einer Notlösung behelfen:

Du registrierst einen zweiten Kanal auf dem Client mit einem festen Port. Die Instanz von TestClass veröffentlichst Du direkt über Marshal. Dem Server brauchst Du nur noch den Aufruf-URL zu schicken. Der Server verwendet den URL und besorgt sich so einen Proxy von TestClass. Ist zwar etwas umständlich, könnte aber klappen.

Rumpel Themenstarter:in
40 Beiträge seit 2007
vor 16 Jahren

Am Client die Implementierung von TestClass, aber am Server nur das Interface. Implementierung und Schnittstelle in separaten Assemblies. Hast Du das genau so probiert?

Exakt so hab ich es gemacht.

Der Server läuft auf einem Linux-Debian-System, mit der aktuellsten Version. Compiliert habe ich schon mit .net und mono - keine Verbesserung.

Es funktioniert nur wenn der Server auf den Client einen Channel eröffnet.

Reichlich seltsam das ganz, ich werde noch ein paar Test durchführen. Falls ich noch was finde werde ich es mitteilen.

Ursprünglich ging es einfach darum alle Clients zu Informieren wenn sich ein bestimmter Status auf dem Server ändert. Vielleicht löse ich es über einen eigenen Socket und UDP-Nachrichten. Ist momentan auch nicht dringend, ich hasse es nur wenn ungelöste Probleme im Projekt sind 🙂

Trotzdem, danke für die Hilfe!