Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
- Subject: Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
- From: Neil Clayton <email@hidden>
- Date: Thu, 15 Feb 2007 12:47:17 +1300
Hi All :-)
I'm trying to do simple client/server, whereby a UI starts up a
server process, sends it messages via NSConnection (DO), and the
server responds back (but not as a return to the original method
call) by calling methods on the client.
The client spawns the server process using fork/exec, and passes it a
port name to use.
The server, a command line cocoa app, on the main thread executes:
NSConnection *connection = [NSConnection defaultConnection];
[connection setRootObject:delegate];
[connection enableMultipleThreads];
[connection setReplyTimeout:5];
[connection setRequestTimeout:5];
if(![connection registerName:[self identifier]]) {
[NSException raise:@"CantPublish" format:@"Cannot publish self as
a server, with name %@", [self identifier]];
}
in order to register itself.
Once out of this code, the server blocks, continually running the
event loop like so:
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while(running && [runLoop runMode:NSDefaultRunLoopMode beforeDate:
[NSDate distantFuture]]);
The client, after spawning the server and waiting to make sure the
message port exists, gets a reference to the server via:
NSConnection *connection = [NSConnection
connectionWithRegisteredName:portName host:nil];
id proxy = [connection rootProxy];
[proxy setProtocolForProxy:@protocol(ExporterServer)];
return proxy;
It then does the following (on the main thread):
[server setClient:self];
[server startProcessing:[[ExportParameters alloc]
initWithCompressionJob:self]];
It's worth me pointing out that the server doesn't just "do work" and
then return. It attempts to convey it's progress back to the client
at the same time, hence needing the setClient: call. Here's the
current server implementation.
- (oneway void) startProcessing:(ExportParameters*)parameters {
[self log:@"Starting export of movie, using %@", parameters];
// Sit here and count to 100 with random time delays
for(int i = 0; i < 100; i++) {
[client progressUpdate:i];
[self log:@"Got to %d", i];
sleep(1);
i += rand() / (RAND_MAX / 5);
}
}
The client is passing itself by reference (proxy) to the server, so
that the server can talk back to it. Both of the method calls are
marked as oneway on the protocol, and on the implementation. The
client proxy is retained on the server (in a normal retain/release way).
The client It then requests that the server do some work via the
startProcessing: call.
On the server side, I can see that the client reference is set (via
logging).
As expected, the method call on the client also returns.
I can also successfully step over the method startProcessing: in the
debugger - after which things go horribly wrong.
a) After stepping over, and hitting "continue" - the debugger then
shows an exception occurring.
#0 0xffff8284 in objc_msgSend_rtp ()
#1 0x9295e5d4 in -[NSDistantObject release] ()
#2 0x9293d968 in NSPopAutoreleasePool ()
#3 0x92959950 in __NSFireMachPort ()
#4 0x907ea820 in __CFMachPortPerform ()
#5 0x907ea734 in __CFRunLoopDoSource1 ()
#6 0x907dce4c in __CFRunLoopRun ()
#7 0x907dc47c in CFRunLoopRunSpecific ()
#8 0x93208740 in RunCurrentEventLoopInMode ()
#9 0x93207dd4 in ReceiveNextEventCommon ()
#10 0x93207c40 in BlockUntilNextEventMatchingListInMode ()
#11 0x9370bae4 in _DPSNextEvent ()
#12 0x9370b7a8 in -[NSApplication
nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#13 0x93707cec in -[NSApplication run] ()
#14 0x937f887c in NSApplicationMain ()
#15 0x000062ac in main (argc=1, argv=0xbffff950) at /Users/neil/
Development/Kompressa/main.m:13
#16 0x00002260 in _start ()
b) The startProcessing method is never actually called on the server.
c) The UI (client) sits in what appears to be an event loop, waiting
for the startClient or startProcessing methods to return. The former
is a 3 line retain/release and so returns immediately, the later does
some work over 100s or so.
I've very confused now. At one point (I tried using runInNewThread
on the client connection) I got it to "work", but then the client
sits there at about 70-90% CPU! Using enableMultipleThreads didn't
seem to help. I've tried putting the server message side into it's
own thread, putting the client in it's own thread, and both of these
scenarios. If I put the client connection in it's own thread, the
server can't talk back to it - I presume because the thread is very
short lived, and that the proxy handed over to the server via
setClient: contains some reference to the thread as well.
This whole thing seems so much more complex than it should. The API
seems clear enough, where am I going wrong? Does this stuff just not
work using the main event loop? I feel like I'm missing something
really, really obvious.
---
Regards,
Neil Clayton
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden