views:

142

answers:

1

I'm new to network programming, and am basically learning-by-doing. I'm folling Mike Ashes program "Sphere Net" from iPhone Cool Projects. I understand what's going on in the program, but I'm ready to start extending it and I expect to be sending a reasonable variety of packet types (each represented as a struct). It doesn't seem rignt to declare different methods for each type of packet.

If I were dealing with objective-c classes, I'd have the functions take the super class as a parameter, or use id. But since I'm using by-value structs I don't think I can use this strategy.

I'm asking for pointers to a good reference explaining how a typical program might handle a possible wide variety of packet (struct) types be it a book, link, or stack overflow answer.

(translation: I don't want to write several entire new methods, that are almost the same, except for the type of packet they deal with everytime I decide to add a new type of packet)

For reference the basic outline of a Sphere Net type program is in the header:

typedef struct { 
    uint32_t identifier; 
    uint32_t datatype; 
} PacketHeader; 

typedef struct { 
    PacketHeader header; 
    int32_t dataItem1;
    int32_t dataItem2;
} MyPacket;
static const uint32_t kPacketIdentifier = 'pkt';

in the implementation:

-(void) init{
// do all the setup, open the sockets, start bonjour.
        // start the listener thread 
        [NSThread detachNewThreadSelector:@selector(listenThread) toTarget:self withObject:nil]; 
}

- (void)objectOfInterestChanged:(ObjectOfInterest *)interestingObject { 

    PositionPacket packet; 

     packet.dataItem1 = CFSwapInt32HostToBig(round(interestingObject.someFloat)); 
     packet.dataItem2 = CFSwapInt32HostToBig(round(interestingObject.someFloat)); 

    [self sendUpdatePacket:packet]; 
} 

- (void)sendUpdatePacket:(MyPacket)packet{ 

    packet.header.identifier = CFSwapInt32HostToBig(kPacketIdentifier); 
    packet.header.datatype = CFSwapInt32HostToBig(kPacketType); 

    for(NSNetService *service in _services) 
        for(NSData *address in [service addresses]) 
            sendto(_socket, &packet, sizeof(packet), 0, [address bytes], [address length]); 
}

- (void)listenThread { 
    while(1) 
    { 
        MyPacket packet; 
        struct sockaddr addr; 
        socklen_t socklen = sizeof(addr); 
        ssize_t len = recvfrom(_socket, &packet, sizeof(packet), 0, &addr,  &socklen); 
        if(len != sizeof(packet)) 
            continue; 
     if(CFSwapInt32BigToHost(packet.basePacket.header.identifier) != kPacketIdentifier)
            continue; 
        //if(CFSwapInt32BigToHost(packet.basePacket.header.datatype) != kPacketType)
        //    continue; 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
        NSData *packetData = [NSData dataWithBytes:&packet length:sizeof(packet)]; 
        NSData *addressData = [NSData dataWithBytes:&addr length:socklen]; 
        NSArray *arguments = [NSArray arrayWithObjects:packetData, addressData, nil]; 
        //SEL mainThreadSEL = @selector(mainThreadReceivedPositionPacket:); 
     SEL mainThreadSEL; 
        if(CFSwapInt32BigToHost(packet.basePacket.header.datatype) == kPacketType)
      mainThreadSEL = @selector(mainThreadReceivedPacket:); 
     [self performSelectorOnMainThread:mainThreadSEL withObject:arguments waitUntilDone:YES]; 
        [pool release]; 
    } 
} 

- (void)mainThreadReceivedPacket:(NSArray *)arguments { 
    // extract the objects from the array created above 
    NSData *packetData = [arguments objectAtIndex:0]; 
    NSData *addressData = [arguments objectAtIndex:1]; 
    const MyPacket *packet = [packetData bytes]; 

   // ...accounting for differences in endianness 
    int32_t x = CFSwapInt32BigToHost(packet->dataItem1); 
    int32_t y = CFSwapInt32BigToHost(packet->dataItem2); 

    AnObject *update;
    update.interestingUpdate = CGThingMake(x, y);  

    [delegate networkController:self didReceiveUpdate:update fromAddress:addressData]; 
}
A: 

After some research a hand-holding I arrived a a solution. It's basically like this:

create specific packets with specific information create a "transmission" packet that's a struct made like:

typedef struct TransmissionStruct{
  size_t typeOfPacketIdentifier;
  char arrayOfBytesHoldingSpecificStruct [<sizeoflargeststruct>]
} Transmission Struct

you then use memcopy(const void*, const void*, size); to copy the data of the specific structs in the char array of the transimssion struct.

Then on the receiving end, you know that the first for bytes of whatever you receive is going to be the type identifier, so read the first four byes, and from there you can decide what to do with the rest of the bytes.

An example of this is at: http://stackoverflow.com/questions/1781698/iphone-problem-receiving-udp-packets

SooDesuNe