objective-cmacosnssocketport

NSSocketPort port only works one way


I am trying to create a connection between two applications on the same computer with a NSSocketPort, but it only seems to be working one way. I have a server that creates a NSMutableDictionary and sets it as the rootObject. The client reads the rootProxy and gets the dictionary as the server created it. But then I want the client to add an additional key/value set to the dictionary and set the dictionary as the rootObject again. But the server does not seem to receive the last value/key set after the client has set it.

Server:

self.portRecv = [[NSSocketPort alloc] initWithTCPPort:30028];
self.conn = [NSConnection connectionWithReceivePort:self.portRecv sendPort:nil];
self.data = [NSMutableDictionary dictionary];
[self.data setObject:@"Value" forKey:@"serverSet"];
self.conn.rootObject = self.data;
self.conn.delegate = self;

This is how the server reads the value:

self.data = (NSMutableDictionary*)[self.conn rootProxy];

Client:

self.portSend = [[NSSocketPort alloc] initRemoteWithTCPPort:30028 host:@"127.0.0.1"];
self.conn = [NSConnection connectionWithReceivePort:nil sendPort:self.portSend];
self.conn.delegate = self;
self.data = (NSMutableDictionary*)[self.conn rootProxy];
[self.data setObject:@"Value" forKey:@"clientSet"];
self.conn.rootObject = self.data;

The client's self.data receives the "serverSet : Value" just fine, but when I let the server read the [self.conn rootProxy] after the client has set the "clientSet : Value" the server gets a dictionary with the serverSet value and not the clientSet.

I am answering the delegate messages as below:

- (BOOL)makeNewConnection:(NSConnection *)conn sender:(NSConnection *)ancestor
{
    return YES;
}

- (BOOL)connection:(NSConnection *)ancestor shouldMakeNewConnection:(NSConnection *)conn
{
    return YES;
}

- (BOOL)connection:(NSConnection *)conn handleRequest:(NSDistantObjectRequest *)doReq
{
    NSInvocation *invocation = [doReq invocation];
    [invocation invoke];

    if ([invocation selector] == @selector(entitiesByName))
    {
        id retVal;
        [invocation getReturnValue:&retVal];

        NSDictionary *rebuilt = [NSDictionary dictionaryWithDictionary:retVal];
        [invocation setReturnValue:&rebuilt];
    }

    [doReq replyWithException:nil];

    return YES;
}

Shouldn't I be able to add a value and return the rootObject to the server? How can I do that?


Solution

  • I managed to solve this by implementing a class that implements the NSCoding protocol and then use this as the rootObject. By doing that I was able to invoke different methods on the server's object from the client.

    It ended up like this:

    Server:

    int port = 30012;
    self.socketModel = [[SocketModel alloc] init];
    self.socketModel.statusBarUiDelegate = self;
    NSSocketPort* recvPort = [[NSSocketPort alloc] initWithTCPPort:port];
    self.conn = [NSConnection connectionWithReceivePort:recvPort sendPort:nil];
    [self.conn setRootObject:self.socketModel];
    

    SocketModel:

    @interface SocketModel : NSObject<NSCoding>
    -(NSString*)performTask:(NSString*)data;
    -(void)taskCompleted;
    @end
    

    Client:

    NSString* data = @"pewpew";
    NSSocketPort* recv = [[NSSocketPort alloc] initRemoteWithTCPPort:30012 host:@"127.0.0.1"];
    self.conn = [NSConnection connectionWithReceivePort:nil sendPort:recv];
    [self.conn setRequestTimeout:5];
    NSString* result = nil;
    SocketModel* obj = nil;
    
    obj = (SocketModel*)[self.conn rootProxy];
    result = [builderObj performTask:data];
    [obj taskCompleted];
    

    I was even able to create a delegate on my SocketModel and assign it to my client, which made the server provide progress info to the client.