2009-11-18 91 views
0

我是網絡編程新手,基本上是在邊幹邊學。我正在翻唱Mike Ashes節目「Sphere Net」從iPhone Cool Projects。我明白程序中發生了什麼,但我已經準備好開始擴展它,我希望發送一個合理的數據包類型(每個都表示爲一個結構體)。爲每種類型的數據包聲明不同的方法似乎並不困難。通過UDP傳遞結構弱類型

如果我正在處理objective-c類,那麼我會讓函數將超類作爲參數,或者使用id。但是由於我使用的是價值結構,我不認爲我可以使用這種策略。

我在問一個很好的參考指針,解釋一個典型的程序如何處理可能的各種各樣的數據包(結構)類型,無論是書籍,鏈接還是堆棧溢出答案。

(翻譯:我不想寫一些全新的方法,這幾乎是相同的,只是他們在處理每次數據包的類型,我決定增加一個新類型的數據包)

對於引用球網類節目的基本輪廓是在標題:

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'; 
在實施

-(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]; 
} 

回答

0

一些研究手把手後我到了一個解決方案。它基本上是這樣的:

創建具有特定信息 創建一個「傳輸」數據包,這是一個結構體等製成的特定數據包:

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

然後使用memcopy(const void*, const void*, size);特定結構的數據複製的字符transimssion結構的數組。

然後在接收端,你知道接收到的任何字節的第一個將是類型標識符,所以請閱讀前四個字節,然後從中決定如何處理剩餘的字節字節。

這方面的一個例子是: iphone problem receiving UDP packets