在objc中,我们可以很简单的通过分布式对象实现线程与线程,进程与进程,以及机器与机器之间进行对象的交互:Portable Distributed Objects。 你可以通过"vend" 服务器发布分布式对象访问接口, 从而达到"vend"对象到远程接口。
"vend": 叫卖,“vend” 服务器有点像一个卖场,任何商家都可以通过注册入场将自己的产品进行销售, 并且这个卖场基于三种类型:1) 卖物理产品(NSMachBootstrapServer),这种产品只许内部销售,通过提供的产品使用其功能。2)卖服务(NSMessagePortNameServer),不提供物理产品,用户通过叫服务的方式使用产品功能,同1)一样,只允许内部销售。3)远程物理产品(NSSocketPortNameServer), 这种产品可以与其它卖场进行销售。
与之对应的产品或渠道有:1) NSMachPort. 2) NSMessagePort. 3) NSSocketPort.
由上我们可以这样理解"vend"服务端,它通过名称向系统注册服务类型,1) 和 2)只能在本地机器使用,即线程或进程间使用, 1) 提供的是注册时所对应的对象,远程客户端像使用本地对象一样使用该项对象。2) 提供的是基于消息的服务,不提供远程访问对象。 3) 提供机器与机器间的对象访问,基于socket的网络编程。
下面我们先看几个例子:
HelloPDOClient.h
#import <Foundation/Foundation.h> @interface HelloPDOClient:NSObject { id serverObject; } - (void) connect; - (void)log:(NSString*)string; @end
HelloPDOClient.m
#import "HelloPDOClient.h" @implementation HelloPDOClient - (void) connect { serverObject=[NSConnection rootProxyForConnectionWithRegisteredName:@"MyServer" host: nil]; } - (void)log: (NSString*)string { [serverObject log: string]; } @end
Client.m
#import "HelloPDOClient.h" main() { NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; Client* client=[[Client alloc] init]; [client connect]; [client log:@"Hello, world!"]; [pool release]; }
HelloPDOServer.h
#import <Foundation/Foundation.h> @interface HelloPDOServer:NSObject { NSConnection * serverConnection; } - (void)log:(NSString*)string; - (void)serve; - NSConnection createConnectionName:(NSString*)name; @end
HelloPDOServer.m
#import "HelloPDOServer.h" @implementation HelloPDOServer - (void)log: (NSString*)string { NSLog (string); } - (void)serve { serverConnection=[self createConnectionName:@"MyServer"]; [[NSRunLoop currentRunLoop] run]; } - (NSConnection*) createConnectionName:(NSString*)name { NSConnection* newConnection=[[NSConnection alloc] init]; if ([newConnection registerName:name]) { [newConnection setRootObject:self]; } else { [newConnection release]; newConnection=nil; } return newConnection;} @end
Server.m
#import "HelloPDOServer.h" main() { NSAutoreleasePool* pool=[[NSAutoreleasePool alloc] init]; Server* server=[[Server alloc] init]; [server serve]; [pool release]; }
好,上面是一个最简单的分布式对象访问程序,在两个进程中共享对象,了解了这一点,我们现在开始对上面程序进行改变,使用NSPort的派生类NSMachPort和NSSocketPort.
1) 服务端
a. NSMachPort
NSPort *receivePort = [[NSMachPort alloc] init];
b. NSSocketPort
NSPort *receivePort = [[NSSocketPort alloc] initWithTCPPort:8080];
然后修改NSConnection, 使其使用NSPort。
NSConnection *conn = [[NSConnection alloc] initWithReceivePort:receivePort sendPort:nil];
使用NSMachPort或NSMessagePort都需要在本地注册服务名称,即调用NSConnection对象的registerName:, 而NSSocketPort由于是远程tcp访问,所以不需要注册本地服务名。
NSConnection将NSPort自动加入到RunLoop(消息队列, 下章将讲解)中,从而监控客户端的调用
最后,启用NSRunLoop.
[[NSRunLoop currentRunLoop] run];
2) 客户端
a. NSMachPort
NSPort *sendPort = [[NSMachBootstrapServer sharedInstance] portForName:@"MyServer" host:nil];
b. NSSocketPort
NSPort *sendPort = [[NSSocketPort alloc] initRemoteWithTCPPort:8080 host:@"serverHostName"];
下面通过NSConnection连接服务器:
NS_DURING NSConnection* conn = [[NSConnection alloc] initWithReceivePort:(NSPort*)[[sendPort class] port] sendPort:sendPort]; id proxyObj = [conn rootProxy]; NS_HANDLER proxyObj = nil; NS_ENDHANDLER
这样就可以直接使用proxyObj了。 由上我们不难理解,NSPort就是底层通信通道,它有三种类型的通信通道,分别是NSMachPort, NSMessagePort, 和NSSocketPort.