Avatar billede cogitans Nybegynder
01. juni 2007 - 11:40 Der er 28 kommentarer

Et eksempel på remoting

Jeg er ved at implementere et eksempel i remoting, som jeg har fundet på netet. Men jeg kan ikke få det til at virke. Jeg benytter ok ikke den rigtige fremgangsmåde. Dette er opskriften, som jeg har fulgt:

A Complete Remoting Example
Let's look at an example of a remote component that provides the time on the server. Such a component could be used to synchronize clients with a central server.
Server Class
We'll need to first write the server class, which provides the implementation of methods to be called remotely. As mentioned previously, a component that is intended to be called remotely must derive from MarshalByRefObject. A single method, GetServerTime(), will return the server time, formatted as a string so that we can display it on the client. Here is the complete sourcecode for our server component:
using System;

namespace RemotingExample
{
    //Remote Server Class
    public class TimeServer : MarshalByRefObject
    {
        //Method to Be Called Remotely By Client
        public string GetServerTime()
        {
            return DateTime.Now.ToString();
        }
    }
}
Server Wrapper
Once we have the Server class implemented, we need to provide a wrapper class that registers a new channel for requests, and indicates the server class containing the remote method implementations. [Note: If you are using Visual Studio.NET, you will need to add a reference to the System.Runtime.Remoting assembly.]
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;

namespace RemotingExample
{
    public class TimeServerWrapper
    {
        public static void Main()
        {
            //Register New Channel
            TcpChannel objChannel = new TcpChannel(8765);
            ChannelServices.RegisterChannel(objChannel);
   
            //Register Server
            RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("RemotingExample.TimeServer,timeserver"), "TimeServerURI", WellKnownObjectMode.SingleCall);

            //Wait for Connections
            Console.WriteLine("Waiting for connections. Press any key to exit.");
            Console.ReadLine();
        }
    }
}
Client
A client calling a remote component needs to register a channel on it's end for the communication, and then use the Activator object to get an instance of the component.
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;

namespace RemotingExample
{
    public class TimeServerWrapper
    {
        public static void Main()
        {
            //Register New Channel
            TcpChannel objChannel = new TcpChannel();
            ChannelServices.RegisterChannel(objChannel);
   
            //Get Instance of Server Object
            TimeServer objOurTimeServer = (TimeServer)Activator.GetObject(typeof(RemotingExample.TimeServer), "tcp://localhost:8765/TimeServerURI");

            //Call Remote Method
            Console.WriteLine(objOurTimeServer.GetServerTime());
        }
    }
}
The following batch file is used to compile all three applications:
csc /t:library /debug /r:System.Runtime.Remoting.dll TimeServer.cs
csc /t:exe /r:TimeServer.dll /debug /r:System.Runtime.Remoting.dll TimeServerWrapper.cs
csc /t:exe /r:TimeServer.dll /debug /r:System.Runtime.Remoting.dll TimeClient.cs
In order to run the example, we first must run the TimeServerWrapper server executable (TimeServerWrapper.exe) to start listening for connections.

Next, in another command window, we run TimeClient.exe. Assuming the correct port numbers and object URIs are configured, the client will display the time on the server.

Once you have a server wrapper that uses the HttpChannel, try this exercise. Start up the server wrapper so that it is listening for connections. Now, open a browser, and enter in the location of the service, as set by your port number and object URI, followed by ?WSDL. In a modified version of our TcpChannel example, this would be "http://localhost:8765/TimeServerURI?WSDL". The screenshot below shows the WSDL for our server component. If you think about it, a remotely activated component over HTTP is the definition of a web service.

Hvad gør jeg forkert? Kendes en let og ligetil fremgangsmåde på dansk?
Avatar billede arne_v Ekspert
01. juni 2007 - 15:23 #1
Avatar billede cogitans Nybegynder
01. juni 2007 - 17:56 #2
Nej, det har jeg ikke. Men er de eksempler i artiklen ligeså omfattende, som dem jeg har skrevet her i spørgsmålet?
Avatar billede arne_v Ekspert
01. juni 2007 - 18:30 #3
mere
Avatar billede arne_v Ekspert
01. juni 2007 - 18:33 #4
men om de er bedre er jeg ikke den rette til at vurdere
Avatar billede cogitans Nybegynder
10. juni 2007 - 15:37 #5
Nu har jeg forsøgt at implementere eksemplerne. Men de giver nogle få problemer.
Det er lykkedes mig at få antal fejl reduceret til disse 2:

1:
The type or namespace name 'Tcp' does not exist in the namespace 'System.Runtime.Remoting.Channels' (are you missing an assembly reference?)

2:
The type or namespace name 'Common' does not exist in the namespace 'X' (are you missing an assembly reference?)

Hvordan får jeg elimineret disse 2 fejl?
Avatar billede cogitans Nybegynder
10. juni 2007 - 15:39 #6
(jeg har ikke kompileret vha. prompt-kommandoerne, som er skrevet i eksemplerne. Prompten kan ikke forstå "csc". Så jeg har blot kompileret inde i Visual Studio 2005.)
Avatar billede arne_v Ekspert
10. juni 2007 - 16:16 #7
Hvis du vil builde command prompt skal du have sat PATH op.

PATH=C:\WINDOWS\MICROS~1.NET\FRAMEW~1\V20~1.507;C:\PROGRA~1\MICROS~1.NET\SDK\v2.0\bin;%PATH%

virker for mig.
Avatar billede arne_v Ekspert
10. juni 2007 - 16:17 #8
Eksemplet antager 4 projekter:
  Library som giver X.dll
  Library som giver XImpl.dll
  Console app XClient.exe
  Console app XServer.exe
Avatar billede arne_v Ekspert
10. juni 2007 - 16:19 #9
XImpl og XClient projekterne skal have ref til X.dll
Avatar billede arne_v Ekspert
10. juni 2007 - 16:22 #10
TCPClinetChannel er i system.runtime.remoting.dll
Avatar billede cogitans Nybegynder
11. juni 2007 - 19:05 #11
Nu har jeg foretaget ændringerne. Men når jeg nu kører X.Server, så får jeg fejlen:

.Config file 'XServer.exe.config' cannot be read successfully due to exception 'System.IO.FileNotFoundException: The system cannot find the file specified. (Exception from HRESULT: 0x80070002)

i linien:
RemotingConfiguration.Configure("XServer.exe.config"); 

Er dette pga, at systemet er Vista? Da Vista jo har nogle mere vidtgående rettigheder - f.eks. skal man starte et prompt-vindue vha. "run as administrator" hvis man vil bruge forskellige kommandoer, som man i tdligere windowsversioner ikke havde problemmer med?
Avatar billede arne_v Ekspert
11. juni 2007 - 19:13 #12
ligger XServer.exe.config i samme dir som XServer.exe ?
Avatar billede cogitans Nybegynder
11. juni 2007 - 19:21 #13
Ja, det skulle jeg da mene. Jeg har lavet filen på samme må som XServer.cs.
Skal namespace "X.Server" tilføjes som reference til config'en?
Avatar billede cogitans Nybegynder
11. juni 2007 - 19:23 #14
Eller skal den absolutte sti til filen angives ved læsning af indholdet?
Avatar billede arne_v Ekspert
11. juni 2007 - 19:38 #15
De skal ligge i samme dir.

Og XServer.exe og XServer.cs ligger naeppe i samme dir - den skal i samme dir som .exe
ikke i samme dir som .cs !
Avatar billede cogitans Nybegynder
11. juni 2007 - 19:54 #16
Ahh, selvfølgelig ja :-)
Avatar billede cogitans Nybegynder
11. juni 2007 - 20:14 #17
Nu har jeg kompileres linien
csc /optimize+ /t:library /out:x.dll X.cs
hvilket gik fint. Så går jeg over i biblioteket
X.Impl
og forsøger
csc /optimize+ /t_library /r:x.dll /out:XImpl.dll XImpl.cs
som så giver fejlen:
error CS0006: Metadata file 'x.dll' could not be found

x.dll er har jeg både tilføjet med den angivne csc-kommando i prompten, samt inde i Visual Studio 2005.
Avatar billede cogitans Nybegynder
26. juni 2007 - 10:05 #18
Jeg har valgt, at prøve et andet eksempel. Men stadig med meget fra disse eksempler. Men allerede ved de første lilnier, giver det store problemer.

Compileren vil godt acceptere:
using System.Runtime.Remoting.Channels;
men den kan ikke finde:
using System.Runtime.Remoting.Channels.Tcp;

Hvordan kan dette være? Disse linier er da nødvendige for projektet? Kan linierne kun bruges i windows-aplikationer eller hvordan?
Avatar billede arne_v Ekspert
26. juni 2007 - 14:11 #19
re 11/6>

Hvis X.dll ikke ligger i current dir skal der fuld sti til.
Avatar billede arne_v Ekspert
26. juni 2007 - 14:14 #20
re 26/6>

Prøv med en ref til system.runtime.remoting.dll
Avatar billede cogitans Nybegynder
26. juni 2007 - 15:00 #21
Jeg har lavet en reference til system.runtime.remoting, men når jeg kompilerer koden, som bl.a. indeholder linien:
TcpServerChannel
så sigen den:
The type or namespace name "TcpServerChannel" could not be found (re you missing a using directive or an asenmbly reference)

Så systemet har ikke rigtig fat i remoting-namespacet. Hvad kan der gøres ved det? Det er i VS2005.
Avatar billede cogitans Nybegynder
27. juni 2007 - 12:19 #22
Jeg fik lige den ide, at sætte "allow remoring connection" til "true" inde i controlpanel->system and maintenacne->system->Remote settings.
Og efter jeg har gjort det, kommer der nu "tcp" og "http" frem, når jeg dot'er mig in på yderligere valgmuligheder efter system.runtime.remoting.channels i VS2005 :-)
Avatar billede cogitans Nybegynder
28. juni 2007 - 13:11 #23
Nu har jeg lavet en aspx-side, som ser sådan ud:

protected void Page_Load(object sender, EventArgs e)
{
  Server ser = new Server();
  Client cli = new Client();
  TextBox1.Text=(string)cli.kald();
}

Det er det hele.
Så har jeg lavet følgene klasser:

public class Hello : MarshalByRefObject
    {
        public Hello()
        {
            Console.Out.WriteLine("\nEr nu i konstruktøren!\n");
        }

        public string HelloWorld()
        {
            Console.Out.WriteLine("\nEr nu i metoden!\n");
            return "\nHar kaldt metoden!\n";
        }
    }

og

public class Client
{
public string kald()
        {
            string besked = "fejl";
            try
            {
                ChannelServices.RegisterChannel(new TcpClientChannel());
                Hello h = (Hello)Activator.GetObject(typeof(Hello),
                    "tcp://localhost:4242/Hello");
                besked = h.HelloWorld().ToString();
                return besked;
            }
            catch (Exception e)
            {
                Console.Out.WriteLine("\n" + e.ToString() + "\n");
            }
            return besked;
        }
    }

og

public class Server
    {
        [STAThread]
        public static void Main()
        {
            TcpServerChannel tc = new TcpServerChannel(4242);
            ChannelServices.RegisterChannel(tc);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(Hello),
                "Kald", WellKnownObjectMode.SingleCall);
            Console.Out.WriteLine("\nTo stop the application, press a key!\n");
            Console.In.ReadLine();
        }
    }

Hvorfor vil dette ikke køre? Der bliver lavet en fejl i try-blokken i client.cs. Kan man ikke kalde main på disse måder?
Avatar billede cogitans Nybegynder
28. juni 2007 - 13:22 #24
Fejlen kommer i:
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in mscorlib.dll

System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused itServer stack trace:    at System.Net.Sockets.Socket.Connect(IPAddress[] addresses, Int32 port)  at System.Runtime.Remoting.Channels.RemoteConnection.CreateNewSocket(AddressFamily family)  at System.Runtime.Remoting.Channels.RemoteConnection.CreateNewSocket()  at System.Runtime.Remoting.Channels.SocketCache.GetSocket(String machinePortAndSid, Boolean openNew)  at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.SendRequestWithRetry(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream)  at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, ITransportHeaders& responseHeaders, Stream& responseStream)  at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)Exception rethrown at [0]:    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)  at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)  at OpsamlingWeb.Remoting.Hello.HelloWorld()  at OpsamlingWeb.Remoting.Client.kald() in C:\Users\User\Documents\Visual Studio 2005\Projects\OpsamlingWeb\OpsamlingWeb\Remoting\Client.cs:line 35
Avatar billede cogitans Nybegynder
28. juni 2007 - 13:37 #25
Måske er det porten 4242, som ikke er åbnet i systemet. Hvordan checker jeg, hvilke portnumre der kan benyttes?
Avatar billede arne_v Ekspert
30. juni 2007 - 21:13 #26
Det afhænger jo af de firewalls og routers kaldet skal igennem.
Avatar billede cogitans Nybegynder
02. juli 2007 - 12:41 #27
De eneste firewalls, er vistas' indbyggede. Routere er der ingen af, og antivirus er Avast.
Men det er vel heller ikke sikkert, at problemet består af blokkerede porte?
Avatar billede cogitans Nybegynder
02. juli 2007 - 13:46 #28
Nu har jeg fundet et andet remotingeksempel på nettet. Og det har jeg endelig fået til at virke.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester