Re: Distributed Objects pitfalls and strategies (SOLUTION (?))
Re: Distributed Objects pitfalls and strategies (SOLUTION (?))
- Subject: Re: Distributed Objects pitfalls and strategies (SOLUTION (?))
- From: John Scalo <email@hidden>
- Date: Tue, 30 Mar 2004 17:31:39 -0800
Thanks to everyone who took some time contribute to the discussion,
especially Wade. And sorry if my responses tended to be of the "I
already tried that!" nature. I really did try lots and lots of
variations on the theme.
I'm hesitant to say I've found the solution, but early testing is
looking really good! So here goes...
If you want to create a distributed objects solution which runs across
a network, uses a fixed port #, deals with multiple user logins,
Panther fast user switches, can vend to multiple clients, and clients
can see multiple servers, here's what seems to work. (This omits
rendezvous discovery, which I'm using but seems straightforward and
trouble-free.)
=== The Server ===
* Be sure to observe NSWorkspaceSessionDidResignActiveNotification
notifications and close your connection when the user of your process
is no longer active. This is related to Panther fast user switching,
and two instances of your server are not going to run correctly on the
same computer if they're serving over the same port.
Then (no error checking for brevity):
int newSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in serverAddress;
int namelen = sizeof(serverAddress);
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = MY_PORT_NUMBER;
int one = 1;
setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
bind(newSocket, (struct sockaddr *)&serverAddress, namelen);
listen(newSocket, 128);
NSSocketPort *newPort = [[NSSocketPort alloc]
initWithProtocolFamily:PF_INET socketType:SOCK_STREAM protocol:0
socket:newSocket];
NSConnection *theConnection = [[NSConnection alloc]
initWithReceivePort:newPort sendPort:newPort];
The key here is to set the SO_REUSEADDR and *not* the SO_REUSEPORT
option. This is what was killing me before. I found other references
suggesting SO_REUSEPORT, but apparently they are wrong. I tried
SO_REUSEADDR on a whim. If you don't do this, then if your server gets
quit and relaunched while there is an active connection, it will take
10 minutes before it can create a new port. Yes, it really is 10
minutes and not 2. I don't know what kernel constant this is tied to,
but it's consistently 10 minutes.
=== The Client ===
Nothing unusual here:
NSString * ipAddressString = NULL; //find this using rendezvous or
whatever
NSSocketPort *connectionPort = [[NSSocketPort alloc]
initRemoteWithTCPPort:MY_PORT_NUMBER host:ipAddressString];
NSConnection *connection = [[NSConnection alloc]
initWithReceivePort:NULL sendPort:connectionPort];
Happy object distributing!
~ John
Is there any reliable and resilient way to set up a DO server/client?
By reliable and resilient, I mean something that can withstand server
stops and starts, multiple user logout/logins, Panther fast user
switching, and deals with multiple clients and servers running on the
same network. It's not hard to get something that works most of the
time, but that's not good enough in this case. I've tried a few
different strategies, but each has its problems. From an earlier
discussion, the solution seemed to be to set up the BSD socket
manually and set the option to allow port reuse. But that introduces
more issues. Here are the things I've tried-
-- Neither client or server is set to reuse ports -- (aka Plain Ol'
Distributed Objects)
i.e. the server does this:
NSSocketPort *newPort = [[NSSocketPort alloc] initWithTCPPort:MYPORT];
NSConnection *connection = [[NSConnection alloc]
initWithReceivePort:newPort sendPort:newPort];
and the client does this:
NSSocketPort *connectionPort = [[NSSocketPort alloc]
initRemoteWithTCPPort:MYPORT host:ipAddressString];
NSConnection *connection = [[NSConnection alloc]
initWithReceivePort:NULL sendPort:connectionPort];
Problems:
* Client hangs when server disappears and then generates timeout
exceptions.
* Server can't make new NSSocketPorts after successive user
logout/logins for about 10 minutes.
-- Server set to reuse ports --
i.e. the server uses initWithProtocolFamily and the client uses
initRemoteWithProtocolFamily, setting up their own BSD socket
bind()ing, and listen()ing. Each calls setsockopt(newSocket,
SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) before binding.
Problems:
* Client hangs and gets timeout exceptions trying to resolve
connections after the server process has been stopped and started
again. e.g., a user logs out and another logs in.
-- Both set to reuse ports --
Problems:
* If there are multiple servers running on the network, then messages
sent to a connection's proxy go to a random server, not necessarily
the one the NSSocketPort was created for.
-- Use dynamic private ports --
Since port #s are unique, there isn't an issue of making new
connections, but this isn't workable if the user has a firewall, or
outside the local network.
So what is the right way to do this?
Thanks
~ John
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.