Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Long answer is: it depends on many things. Short answer is yes. Yes Yes.</p> <p>Let's make an experiment and see the most common default situation. We have 2 console apps and 1 common class library which is referred by both console apps. The 1st console app has the role of the client and the 2nd one has that of the server.</p> <p>First, here's what the commonly depended upon class library contains:</p> <pre><code>public interface IFactory { string Hello(string name); } </code></pre> <p>Now for some server code. Here's the start up:</p> <pre><code>private static TcpChannel channel; static void Main(string[] args) { BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider(); BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider(); serverProv.TypeFilterLevel = TypeFilterLevel.Full; channel = new TcpChannel( properties: new Hashtable { { @"port", 2013 } }, clientSinkProvider: clientProv, serverSinkProvider: serverProv ); ChannelServices.RegisterChannel(channel, false); RemotingConfiguration.RegisterWellKnownServiceType(typeof(Factory), "Factory.rem", WellKnownObjectMode.SingleCall); Console.WriteLine("Server started..."); Console.WriteLine("Press any key to stop..."); Console.ReadKey(intercept: true); } </code></pre> <p>We just mentioned a class called <strong>Factory</strong>.</p> <pre><code>RemotingConfiguration.RegisterWellKnownServiceType(typeof(Factory), "Factory.rem", WellKnownObjectMode.SingleCall); </code></pre> <p>You guessed it. It's the <strong>IFactory</strong> implementation:</p> <pre><code>private sealed class Factory : MarshalByRefObject, IFactory { #region IFactory Members string IFactory.Hello(string name) { return @"Hello " + name + @" !"; } #endregion } </code></pre> <p>Now for some client:</p> <pre><code>static void Main(string[] args) { Console.WriteLine("Press any key to connect..."); Console.ReadKey(intercept: true); IFactory factory = Activator.GetObject(typeof(IFactory), @"tcp://127.0.0.1:2013/Factory.rem") as IFactory; EventWaitHandle signal = new EventWaitHandle(initialState: false, mode: EventResetMode.ManualReset); ThreadStart action = () =&gt; { signal.WaitOne(); var result = factory.Hello("Eduard"); Console.WriteLine(result); }; foreach (var i in Enumerable.Range(0, 99)) new Thread(action) { IsBackground = true }.Start(); Console.WriteLine("Press any key to bombard server..."); Console.ReadKey(intercept: true); signal.Set(); Console.ReadKey(intercept: true); } </code></pre> <p>You already know all of these things, I'm sure. We obtain a transparent proxy to the SingleCall service on the other side (they're both on the same machine and we're using TCP port 2013):</p> <pre><code>IFactory factory = Activator.GetObject(typeof(IFactory), @"tcp://127.0.0.1:2013/Factory.rem") as IFactory; </code></pre> <p>Then, for "simulataneous-ness" reasons we create 100 threads, start them (which can take some time), but "hold them in a leash" (a signal is an essential means of synchronization of the OS) until we "pull the trigger":</p> <pre><code>EventWaitHandle signal = new EventWaitHandle(initialState: false, mode: EventResetMode.ManualReset); ThreadStart action = () =&gt; { signal.WaitOne(); var result = factory.Hello("Eduard"); Console.WriteLine(result); }; foreach (var i in Enumerable.Range(0, 99)) new Thread(action) { IsBackground = true }.Start(); </code></pre> <p>So although all 100 threads have been created <strong>AND</strong> started, they are all waiting in the following invocation:</p> <pre><code>signal.WaitOne(); </code></pre> <p>That way we can get the to start at the same time <strong>better</strong>, otherwise the creation and starting of threads itself would have made their actual execution more or less sequential.</p> <p>We ask the user to decide when to "bombard the server" with 100 Hello invocations:</p> <pre><code>Console.WriteLine("Press any key to bombard server..."); Console.ReadKey(intercept: true); signal.Set(); </code></pre> <p>And this is what happens:</p> <p>1) We start the <strong>server</strong> console app and let it run in peace:</p> <p><img src="https://i.stack.imgur.com/pF3hW.jpg" alt="enter image description here"></p> <p>2) We start the <strong>client</strong> console app, "make the connection" by pressing any key (which is only a logical connection since it just creates a transparent proxy) but we postpone the "bombardment":</p> <p><img src="https://i.stack.imgur.com/PtPik.jpg" alt="enter image description here"></p> <p>3) We start up Mark Russinovich's <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx" rel="noreferrer">Process Explorer</a> and use it to discover the <strong>client</strong> process in the process list, and while doing that we open it's properties window and select the TCP/IP tab:</p> <p><img src="https://i.stack.imgur.com/u51wS.jpg" alt="enter image description here"></p> <p>4) We hit any key in the <strong>client</strong> console app, and .. <strong>TA DAA !!</strong> You get <strong>a lot</strong> of connections in <a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx" rel="noreferrer">Process Explorer</a>. Are they a hundred ? Sometimes yes, sometimes no. It's a connection pool, that's for sure. After a short while (5 to 10 seconds) of idleness they close down which is a very good thing (because the .NET Remoting stack is implemented that way).</p> <p><img src="https://i.stack.imgur.com/CJEEy.jpg" alt="enter image description here"></p> <p>I hope this experiment generally answered your question.</p> <p>In more specific cases and in a more rigorous sense you should check out the documentation and read about the various channels that you might use in your .NET Remoting apps (there are loads of them out there, what you've seen here is just the regular TcpChannel officially provided by Microsoft, it depends on what your .NET Remoting configuration says, on whether you're hosting the server in IIS or not, etc).</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload