2011-01-29 153 views
5

我想通過GameKit發送一些NSData而不是Bluetooth通過GameKit發送和接收NSData

雖然我設置了GameKit並且能夠發送小消息,但我現在想要擴展併發送整個文件。

我一直在閱讀,你必須將大文件拆分成數據包,然後再單獨發送它們。

所以我決定創建一個struct,使其更容易對數據包進行解碼,當他們在另一端會根據收到:

typedef struct { 
    const char *fileName; 
    NSData *contents; 
    int fileType; 
int packetnumber; 
int totalpackets; 
} file_packet; 

然而,對於小文件(8KB和更小)我想一個包就足夠了。

因此,對於一個包,我想我應該能夠創建一個file_packet,設置其屬性,並通過-sendDataToAllPeers發送:withDataMode:錯誤:

NSData *fileData; 
file_packet *packet = (file_packet *)malloc(sizeof(file_packet)); 
packet->fileName = [filename cStringUsingEncoding:NSASCIIStringEncoding]; 
packet->contents = [NSData dataWithContentsOfFile:selectedFilePath]; 
packet->packetnumber = 1; 
packet->totalpackets = 1; 
packet->fileType = 56; //txt document 
fileData = [NSData dataWithBytes:(const void *)packet length:sizeof(file_packet)]; 
free(packet); 

NSError *error = nil; 
[self.connectionSession sendDataToAllPeers:fileData withDataMode:GKSendDataReliable error:&error]; 
if (error) { 
NSLog(@"An error occurred: %@", [error localizedDescription]); 
} 

不過,我不認爲有什麼地方右鍵設置fileData - 和error什麼都不顯示。

當一個文件的接收,我請執行下列操作:

file_packet *recievedPacket = (file_packet *)malloc(sizeof(file_packet)); 
recievedPacket = (file_packet *)[data bytes]; 
NSLog(@"packetNumber = %d", recievedPacket->packetnumber); 
... 

然而,在控制檯上輸出爲packetNumber = 0,甚至當我設置包編號爲1

我缺少明顯的? 我對NSDataGameKit瞭解不多。

所以我的問題是 - 我可以在NSData中添加一個file_packet,如果是這樣,我該如何成功 - 以及如何將文件分成多個數據包?

回答

8

要添加上:

什麼你應該做的,是讓一個NSObject子類來表示你的包,然後採用NSCoding到它序列化到一個NSData在你想要的方式。用結構來做這件事並不是爲了買東西,而是讓事情變得更加困難。這也是脆弱的,因爲將一個結構包裝到NSData中並沒有考慮端到端等問題。

使用NSCoding的打包過程的棘手部分是您不知道什麼是開銷編碼過程是儘可能大,但仍然在最大包的大小是棘手的...

我提出這沒有測試或保修,但如果你想在該方法體面的開始,這可能是它。被警告,我沒有檢查我的任意100字節的開銷是否真實。你將不得不用數字來玩一點。

包。H:

@interface Packet : NSObject <NSCoding> 
    { 
     NSString* fileName; 
     NSInteger fileType; 
     NSUInteger totalPackets; 
     NSUInteger packetIndex; 
     NSData* packetContents; 
    } 

    @property (readonly, copy) NSString* fileName; 
    @property (readonly, assign) NSInteger fileType; 
    @property (readonly, assign) NSUInteger totalPackets; 
    @property (readonly, assign) NSUInteger packetIndex; 
    @property (readonly, retain) NSData* packetContents; 

    + (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents; 

@end 

Packet.m:

#import "Packet.h" 

@interface Packet() 

@property (readwrite, assign) NSUInteger totalPackets; 
@property (readwrite, retain) NSData* packetContents; 

@end 

@implementation Packet 

- (id)initWithFileName: (NSString*)pFileName ofType: (NSInteger)pFileType index: (NSUInteger)pPacketIndex 
{ 
    if (self = [super init]) 
    { 
     fileName = [pFileName copy]; 
     fileType = pFileType; 
     packetIndex = pPacketIndex; 
     totalPackets = NSUIntegerMax; 
     packetContents = [[NSData alloc] init]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [fileName release]; 
    [packetContents release]; 
    [super dealloc]; 
} 

@synthesize fileName; 
@synthesize fileType; 
@synthesize totalPackets; 
@synthesize packetIndex; 
@synthesize packetContents; 

- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    [aCoder encodeObject: self.fileName forKey: @"fileName"]; 
    [aCoder encodeInt64: self.fileType forKey:@"fileType"]; 
    [aCoder encodeInt64: self.totalPackets forKey:@"totalPackets"]; 
    [aCoder encodeInt64: self.packetIndex forKey:@"packetIndex"]; 
    [aCoder encodeObject: self.packetContents forKey:@"totalPackets"]; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if (self = [super init]) 
    {   
     fileName = [[aDecoder decodeObjectForKey: @"fileName"] copy]; 
     fileType = [aDecoder decodeInt64ForKey:@"fileType"]; 
     totalPackets = [aDecoder decodeInt64ForKey:@"totalPackets"]; 
     packetIndex = [aDecoder decodeInt64ForKey:@"packetIndex"]; 
     packetContents = [[aDecoder decodeObjectForKey:@"totalPackets"] retain]; 
    } 
    return self; 
} 

+ (NSArray*)packetsForFile: (NSString*)name ofType: (NSInteger)type withData: (NSData*)fileContents 
{ 
    const NSUInteger quanta = 8192; 

    Packet* first = [[[Packet alloc] initWithFileName:name ofType:type index: 0] autorelease]; 

    // Find out how big the NON-packet payload is... 
    NSMutableData* data = [NSMutableData data]; 
    NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 
    [first encodeWithCoder: coder]; 
    [coder finishEncoding]; 

    const NSUInteger nonPayloadSize = [data length]; 

    NSMutableArray* packets = [NSMutableArray array]; 
    NSUInteger bytesArchived = 0; 
    while (bytesArchived < [fileContents length]) 
    { 
     Packet* nextPacket = [[[Packet alloc] initWithFileName: name ofType: type index: packets.count] autorelease]; 
     NSRange subRange = NSMakeRange(bytesArchived, MIN(quanta - nonPayloadSize - 100, fileContents.length - bytesArchived)); 
     NSData* payload = [fileContents subdataWithRange: subRange]; 
     nextPacket.packetContents = payload; 
     bytesArchived += [payload length];   
     [packets addObject: nextPacket]; 
    } 

    for (Packet* packet in packets) 
    { 
     packet.totalPackets = packets.count; 
    } 

    return packets; 
} 

- (NSData*)dataForSending 
{ 
    NSMutableData* data = [NSMutableData data]; 
    NSKeyedArchiver* coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData:data] autorelease]; 
    [self encodeWithCoder: coder]; 
    [coder finishEncoding]; 
    return [NSData dataWithData:data]; 
} 

+ (Packet*)packetObjectFromRxdData:(NSData*)data 
{ 
    NSKeyedUnarchiver* decoder = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease]; 
    return [[[Packet alloc] initWithCoder:decoder] autorelease]; 
} 

@end 

從這些數據包的原始文件的reassemblage可以使用了很多相同的方法,分裂它做...遍歷的數據包,複製從單個數據包有效載荷NSDatas轉換成一個大的NSMutableData。

最後,我不得不說,當你發現自己在做這樣的事情時,可以歸結爲實現一個原始的TCP堆棧,通常是時候停下來問問是否沒有更好的方法來做到這一點。換句話說,如果GameKit是通過藍牙在設備之間傳輸文件的最佳方式,那麼人們可能會期望API能夠做到這一點,但它具有這個8K限制。

我並不是故意隱晦的 - 我不知道什麼樣的API適合您的情況,但是烹飪這個Packet類的練習讓我想到了,「這裏有更好的方法。」

希望這會有所幫助。

+0

感謝您的回答,但是在測試之後,它似乎崩潰了(EXC_BAD_ACCESS)。不知道如何實現它,因爲我這樣做的方式不起作用 – 2011-01-30 08:58:19

4

您可以創建大小爲sizeof(packet)的NSData,它只是指針的大小。將其更改爲sizeof(file_packet)。

順便說一句,你不是真的發送文件名和內容。只有指向他們的指針。