2011-01-29 103 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)。

顺便说一句,你不是真的发送文件名和内容。只有指向他们的指针。