DO over TCP sockets example for Mac OS X
DO over TCP sockets example for Mac OS X
- Subject: DO over TCP sockets example for Mac OS X
- From: Chris Kane <email@hidden>
- Date: Mon, 9 Jul 2001 10:16:50 -0700
Here is a message I sent to another list several months ago about doing
DO over the network. Now it will be in this list's archives, if it
isn't already.
Chris Kane
Cocoa Frameworks, Apple
Begin forwarded message:
From: Chris Kane <email@hidden>
Date: Fri Feb 02, 2001 03:18:17 PM US/Pacific
To: email@hidden
Subject: DO over TCP sockets example for Mac OS X
Weeks ago now, there was discussion of using DO over TCP, and I said
I'd write up an example. Well, things are very busy here, and I
finally got around to doing that only a couple days ago. The example
assumes you don't need DO explained. It requires Mac OS X Public Beta
or later.
The example is very simple, just a random number server. With
USE_SOCKETS equal to 0, it uses Mach ports, otherwise TCP sockets
(NSSocketPort). Compile with the comment at the top, and make a copy
of the binary, and name one 'client' and one 'server'.
Run the server on the local machine or a remote one. If the client is
started without any arguments, it tries to connect to the server on the
machine the client is running on. Give it the name of the remote host
if the server is running on another machine. Remote only works for TCP
socket transport.
The code is written to illustrate the differences in choosing a
transport with as few differences as possible. See the use of
USE_SOCKETS in the server() function to see its differences. The
client "figures out" which style the server is using by trying Mach
ports, then TCP sockets. (I'm not saying real programs should do that.)
Real-world example: The Mac OS X build system is a complex system for
farming out project builds to build servers and managing dependencies
and whatnot, and it has used DO over TCP for some time, using its own
hand-rolled TCP transport. So DO over TCP is possible. That system
isn't using NSSocketPort yet (it predates NSSocketPort), but we'll be
switching it to NSSocketPort sometime after Mac OS X is released, which
will eliminate several hundreds of lines of code. I've given the
engineers that will do that this same example to work from.
Chris Kane
Cocoa Frameworks, Apple, Inc.
// cc -Wall -g -framework Foundation -O -o server do_test.m; cp server
client
#import <Foundation/Foundation.h>
#if !defined(USE_SOCKETS)
#define USE_SOCKETS 1
#endif
@protocol ServerProtocol
- (void)setRandomSeed:(unsigned int)s;
- (long)getRandom;
@end
@interface Server : NSObject <ServerProtocol>
@end
@implementation Server
- (void)setRandomSeed:(unsigned int)s {
srandom(s);
}
- (long)getRandom {
return random();
}
@end
#define SERVER_PORT 15550
#define SERVER_NAME @"TEST"
void server(int argc, const char *argv[]) {
NSPort *receivePort = nil;
NSConnection *conn;
id serverObj;
#if USE_SOCKETS
receivePort = [[NSSocketPort alloc] initWithTCPPort:SERVER_PORT];
#else
// Mach ports being "anonymous" and need to be named later
receivePort = [[NSMachPort alloc] init];
#endif
conn = [[NSConnection alloc] initWithReceivePort:receivePort
sendPort:nil];
serverObj = [[Server alloc] init];
[conn setRootObject:serverObj];
#if USE_SOCKETS
// registration done by allocating the NSSocketPort
printf("server configured to use sockets\n");
#else
if (![conn registerName:SERVER_NAME]) {
printf("server: set name failed\n");
exit(1);
}
printf("server configured to use Mach ports\n");
#endif
[[NSRunLoop currentRunLoop] run];
}
void client(int argc, const char *argv[]) {
NSPort *sendPort = nil;
NSConnection *conn;
id proxyObj;
long result;
NSString *hostName = nil;
if (1 < argc) {
hostName = [NSString stringWithCString:argv[1]];
}
sendPort = [[NSMachBootstrapServer sharedInstance]
portForName:SERVER_NAME host:hostName];
if (nil == sendPort) {
// This will succeed (if host exists), even when there is no server
// on the other end, since the connect() is done lazily (arguably
wrong),
// when first message is sent.
sendPort = [[NSSocketPort alloc] initRemoteWithTCPPort:SERVER_PORT
host:hostName];
}
if (nil == sendPort) {
printf("client: could not look up server\n");
exit(1);
}
NS_DURING
conn = [[NSConnection alloc] initWithReceivePort:(NSPort
*)[[sendPort class] port] sendPort:sendPort];
proxyObj = [conn rootProxy];
NS_HANDLER
proxyObj = nil;
NS_ENDHANDLER
if (nil == proxyObj) {
printf("client: getting proxy failed\n");
exit(1);
}
[proxyObj setProtocolForProxy:@protocol(ServerProtocol)];
printf("client configured to use %s\n", ([sendPort class] ==
[NSSocketPort self]) ? "sockets" : "Mach ports");
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
printf("\nset seed\n");
[proxyObj setRandomSeed:17];
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
printf("\nset seed\n");
[proxyObj setRandomSeed:17];
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
result = [proxyObj getRandom];
printf("random #: %ld\n", result);
}
int main(int argc, const char *argv[]) {
id pool = [[NSAutoreleasePool alloc] init];
if (0 < argc && 0 == strcmp(argv[0] + strlen(argv[0]) - 6,
"server")) {
server(argc, argv);
} else {
client(argc, argv);
}
[pool release];
exit(0);
}