4

I have a working server/client app using Distributed Objects in objective-c. What I am struggling with right now is making the app multi-threaded. So that more users can access the server at the same time.

Here is main function for the server. This is where I create the nsconnection object.

From my understanding, the way I should approach this is when a user tries to access the server, a new thread should be allocated for that particular call. Should the [conn runInNewThread] takes care of this ?

Any thoughts is appreciated...

Here is the code for the server.

int main (void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

Transactions *trans = [Transactions new];
NSConnection *conn  = [NSConnection defaultConnection];        
[conn setRootObject: trans];
[conn runInNewThread];

if (![conn registerName:@"holycow"]) 
{
    NSLog (@"Failed registering holycow.");
    exit (1);
}

NSLog (@"waiting for connections...");
[[NSRunLoop currentRunLoop] run];

[pool release];
return 0;
}
n3rfd
  • 275
  • 2
  • 11

2 Answers2

0

@Parag Bafna was right in his answer when I ran a test. However, I used a special kind of architecture in the server that may have aided in this. Take for instance a command that takes a long time to run on the server daemon. This can hang a server up a bit and make it much slower for connections to be processed. Here's my solution.

  1. Have the client call an asynchronous class method using the oneway property. Let's call this runProcess.

  2. Make runProcess do a popen() on the task and keep the PID as a global variable.

  3. Then, make it use performSelectorInBackground to run a synchronous class method called readProcess in the background.

  4. In readProcess, I use while(fgets(buff, sizeof(buff), ghPID)!=NULL) to read the previously established popen() output (note the global variable, ghPID) and append the latest line read into a global variable of recent lines read. This method runs as a background task, and the client has already disconnected from runProcess.

  5. Now have the client connect to a synchronous class method called getProcessData. This should then take the global variable of recent lines read and return it back. Since that doesn't take very long to do, the client disconnects from that class method pretty quickly.

  6. The client can then poll that data until it knows it's done. To aid with that, you can create a synchronous method called isProcessRunning that can check on a global boolean variable on the server daemon called gbRunning and return true/false. Of course, though, it will be up to you to flip that variable in the server daemon true/false in the various class methods when the server is busy running a popen() task.

By doing it this way, your server daemon can respond to concurrent requests much faster.

An additional tip would be to use a kill file or other mechanism (shared memory? SIGHUP?) so that if you're in a while loop and you want that process to stop, you can just drop a kill file somewhere in /tmp for instance and the process will use pclose to kill it and then erase the kill file. I also do this before starting a process if I want to ensure only one particular process runs at a time from that server daemon.

Volomike
  • 23,743
  • 21
  • 113
  • 209
0

In order to respond to client messages, the responding server object must be set as the ’root object’ of an instance of the NSConnection class, and this NSConnection must be registered with the network by name.

So in case of Distributed object, single server object can handle multiple clients. or you can create more server object and divide your clients.

Parag Bafna
  • 22,812
  • 8
  • 71
  • 144
  • This seems to be the case for me. I was able to have two client applications call a synchronous (meaning, I didn't use the `oneway` keyword) class method over DO at the same time. It was like it threaded automatically for it. It was a little slow because, well, the server was busy doing something difficult, but when I gave it a sec, the server responded while it was processing the other task simultaneously. I would recommend, however, that coders do something like start a task with a oneway (async) method, then check it with a sync method that runs fast. – Volomike Apr 02 '16 at 06:11