tags:

views:

131

answers:

5

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?

A: 

Do you mean something like Net.TCP port sharing?

Chris Lively
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.
Jonathan.Peppers
A: 

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
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.
Jonathan.Peppers
A: 

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
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.
Jonathan.Peppers
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
A: 

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
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.
Jonathan.Peppers
A: 

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.

Jonathan.Peppers