4

We are currently working on an API for an existing system.

It basically wraps some web-requests as an easy-to-use library that 3rd party companies should be able to use with our product.

As part of the API, there is an event mechanism where the server can call back to the client via a constantly-running socket connection.

To minimize load on the server, we want to only have one connection per computer. Currently there is a socket open per process, and that could eventually cause load problems if you had multiple applications using the API.

So my question is: if we want to deploy our API as a single standalone assembly, what is the best way to fix our problem?

A couple options we thought of:

  • Write an out of process COM object (don't know if that works in .Net)
  • Include a second exe file that would be required for events, it would have to single-instance itself, and open a named pipe or something to communicate through multiple processes
  • Extract this exe file from an embedded resource and execute it

None of those really seem ideal.

Any better ideas?

John Saunders
  • 160,644
  • 26
  • 247
  • 397
jonathanpeppers
  • 26,115
  • 21
  • 99
  • 182
  • 2
    What about a Windows Service running in the background? – dtb Jun 07 '10 at 18:34
  • That is similar to deploying an exe along with an assembly, but would require more work. We were hoping a 3rd party would be able to deploy an application using our API by merely referencing an assembly. We might end up going this route and building an msi/merge-module that 3rd parties would have to install along with their application. – jonathanpeppers Jun 07 '10 at 18:41
  • @Jonathan: please don't repeat tags ("C# .Net") in the title. – John Saunders Jun 07 '10 at 18:51
  • 1
    Windows server supports tens of thousands of simultaneous connections. Have you actually tried to reach this limit and verified that you had a problem? – Hans Passant Jun 07 '10 at 18:55
  • I agree with Hans. Are you sure this is an actual problem? From the server perspective, the load requirements are no different to have multiple apps on the same box vs multiple apps across multiple boxes. And the solution is the same: load balance the api. – NotMe Jun 07 '10 at 19:04
  • We just know that there could be 10+ apps per box, and cutting the number of connections by 90% or more is desirable. Doing this ahead of time is going to save us a lot of trouble in the long-run. – jonathanpeppers Jun 08 '10 at 13:14

5 Answers5

0

Do you mean something like Net.TCP port sharing?

NotMe
  • 87,343
  • 27
  • 171
  • 245
  • I should have mentioned another requirement: our API needs to only be .Net 2.0 to support a wider 3rd party audience. This means WCF isn't possible to be used, we are doing everything via HttpWebRequest or the Socket class for events. – jonathanpeppers Jun 07 '10 at 18:45
0

You could fix the client-side port while opening your socket, say 45534. Since one port can be opened by only one process, only one process at a time would be able to open socket connection to the server.

apoorv020
  • 5,420
  • 11
  • 40
  • 63
  • The client isn't listening, our app would not work through firewalls. The client establishes a connection on the server and waits for output returned by the server, this is how our events work. – jonathanpeppers Jun 08 '10 at 13:08
0

Well, there are many ways to solve this as expressed in all the answers and comments, but may be the simpler way you can use is just have global status store in a place accesible for all the users of the current machine (may be you might have various users logged-in on the machine) where you store WHO has the right to have this open. Something like a "lock" as is used to be called. That store can be a field in a local or intranet database, a simple file, or whatever. That way you don't need to build or distribute extra binaries.

someone
  • 916
  • 1
  • 5
  • 8
  • I think you are assuming this API is read only and doesn't change. Our API serves up real-time data and gives 3rd parties the ability to modify the data. The API also can give real-time events, and this is where our issue lies. – jonathanpeppers Jun 08 '10 at 13:23
  • I see, yes, I assumed an immutability that does not exists in your API. Well, if I have to choose one of the options already expressed I think the clearer option is the one that has a separate process (service or not) managing the connection per machine to the server, and then add to the communication protocol the ability to determine which client process is the real-time event for. Also, that extra-layer will let you extend the logic easily in the future (let's say enable a second communication channel). If you choose this option, have this in mind, net and servers should speed up in future. – someone Jun 08 '10 at 18:38
0

When a client connects to your server you create a new thread to handle him (not a process). You can store his IP address in a static dictionary (shared between all threads). Something like:

static Dictionary<string, TcpClient> clients = new Dictionary<string, TcpClient>();

//This method is executed in a thread
void ProcessRequest(TcpClient client)
{
   string ip = null;
   //TODO: get client IP address

   lock (clients)
   {
      ...
      if (clients.ContainsKey(ip))
      {
         //TODO: Deny connection
         return;
      }
      else
      {
         clients.Add(ip, client);
      }
   }
   //TODO: Answer the client
}
//TODO: Delete client from list on disconnection
Eduardo
  • 5,645
  • 4
  • 49
  • 57
  • Our implementation on the server is irrelevant (and is a Linux server not using anything like C# (Mono) BTW). The problem we want to handle is to reduce the number of connections a client has open to 1 per machine. We want to do this because a client PC may have 10-15 applications using our API at once. – jonathanpeppers Jun 09 '10 at 15:06
0

The best solution we've come up with is to create a windows service that opens up a named pipe to manage multiple client processes through one socket connection to the server.

Then our API will be able to detect if the service is running/installed and fall back to creating it's own connection for the client otherwise.

3rd parties can decide if they want to bundle the service with their product or not, but core applications from our system will have it installed.

I will mark this as the answer in a few days if no one has a better option. I was hoping there was a way to execute our assembly as a new process, but all roads to do this do not seem very reliable.

jonathanpeppers
  • 26,115
  • 21
  • 99
  • 182