2011-01-29 1 views
5

NSDataBluetooth에서 GameKit까지 보내려고합니다.GameKit을 통해 NSData를 보내고 받으십시오.

GameKit을 설정하고 작은 메시지를 보낼 수 있지만 이제 전체 파일을 확장하여 보내고 싶습니다.

커다란 파일을 개별적으로 전송하기 전에 패킷으로 분할해야한다고 읽었습니다. 나는 하나 개의 패킷을 생각 작은 파일 (8킬로바이트 및 이하)에 대한

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

그러나 :

그래서 나는 그들이 다른 끝에서 수신 할 때 쉽게 패킷을 디코딩 할 수 있도록하기 위해 struct을 만들기로 결정 충분할거야. 뭔가가 생각하지 않습니다,

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

그러나 : withDataMode : 오류를

그래서 하나 개의 패킷을 위해, 나는 그것의 속성을 설정하는 file_packet을 만들 수 및 -sendDataToAllPeers로 보내 줄 알았는데 파일 데이터를 올바르게 설정하면 error에 아무 것도 표시되지 않습니다.

때 파일의 수신, 나는 다음을 수행하십시오

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

그러나, 콘솔의 출력은 내가 1

나는 분명 실종에 packetNumber을 설정 한 경우에도, packetNumber = 0입니까? NSData 또는 GameKit에 대해 많이 알지 못합니다.

제 질문은 - NSDatafile_packet을 추가 할 수 있습니까? 그렇다면 어떻게해야합니까? - 파일을 여러 개의 패킷으로 어떻게 분할합니까?

답변

8

에 추가하려면 :

은 당신이 여기에서한다고하는 것은 NSObject의 서브 클래스는 당신의 패킷을 나타내고, 다음 원하는 방법에있는 NSData로 직렬화 NSCoding을 채택 할 수 있도록합니다. 구조체를 사용하여이 작업을 수행하면 아무 것도 사지 않고 상황을 더욱 어렵게 만듭니다. 구조체를 NSData에 패킹하는 것이 엔디안과 같은 것을 설명하지 않기 때문에 깨지기 쉽습니다.

NSCoding을 사용하는 패킷 화 프로세스의 까다로운 부분은 실제로 코딩 과정은 가능한 한 커야하지만 여전히 최대 패킷 크기 아래에있는 것은 까다 롭습니다. ...

테스트 나 보증없이 이것을 제시하지만,이 접근법에 대한 적절한 시작을 원한다면 그것. 경고, 나는 임의의 100 바이트의 오버 헤드가 현실적인지 확인하지 않았다. 숫자를 가지고 놀아야 할 것입니다.

패킷.시간 :

@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가 당신의 상황에 어떻게 될지 모르지만,이 패킷 클래스를 요리하는 운동은 저에게 "더 좋은 방법이 있어야합니다."라고 생각하게했습니다.

희망이 도움이됩니다.

+0

그러나 답변을 주셔서 감사합니다. 테스트를 마친 후 충돌 (EXC_BAD_ACCESS)이 발생했습니다. 내가 그것을하는 방식으로 작동하지 않기 때문에 그것을 구현하는 방법을 모르겠다 –

+0

귀하의 의견을 읽은 후, 나는 autoreleased 개체의 나쁜 사용을 발견했습니다. 다시 시도하고 싶을 수도 있습니다. 그러나 일반적으로 EXC_BAD_ACCESS는 "할당 취소 된 객체와 상호 작용합니다." 악기를 사냥하기 위해 좀비가 켜져있는 Instruments의 Allocations 프로파일을 사용할 수 있습니다. 그것은 매우 귀중합니다! – ipmcc

+0

몇 가지 조정을하면 코드가 완벽하게 작동합니다. 감사. –

4

크기가 인 크기 (패킷) 인 NSData는 포인터의 크기만으로 만듭니다. sizeof (file_packet)로 변경하십시오.

아직은 파일 이름과 내용을 보내지 않았습니다. 그들에 대한 포인터 만.