Re: Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
Re: Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
- Subject: Re: Frustration trying to get NSConnection/NSPort working (feels like it should be simpler ...)
- From: Stephan Cleaves <email@hidden>
- Date: Wed, 14 Feb 2007 20:05:29 -0500
In my experience DO is relatively easy but my caveat right up front
is that I have never dealt with the defaultConnection or a named
port. I always create my own port objects and create the NSConnection
from those. My first comment would be to invest in Advanced Mac OS X
Programming from the guys at Big Nerd Ranch. They cover general
networking as well as DO. My second comment is that your timeouts may
be a bit too short, for the time being try just commenting those out.
Particularly when using the debugger those may be causing issues. I'm
not sure about using sleep(), perhaps NSThread sleepUntilDate: would
be a better choice. My suggestion would be to start with something a
bit more simple, an echo DO call for example. Get the connection code
sorted out so that you actually know you are connecting before you
try to do anything fancy with threads.
I realize I haven't provided you any concrete solutions, but I feel
like I'd need to tinker with your code to do that. Hopefully I've at
least given you some avenues of exploration.
Stephan Cleaves
On Feb 14, 2007, at 6:47 PM, Neil Clayton wrote:
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