And*_*kha 2 tcp objective-c ios gcdasyncsocket
谁能帮我?我通过使用GCDAsyncSocket在TCP协议上密集交换两个设备之间的数据.我发送这样的数据:
NSMutableDictionary *packet = [[[NSMutableDictionary alloc] init] autorelease];
[packet setObject:[NSNumber numberWithInt:MultiPlayerTypeInfoNextRoundConfirm] forKey:@"type_info"];
[packet setObject:[NSNumber numberWithBool:YES] forKey:@"connection_confirmation"];
NSMutableData *data = [[NSMutableData alloc] initWithData:[NSKeyedArchiver archivedDataWithRootObject:packet]]; //[NSKeyedArchiver archivedDataWithRootObject:packet];
if (currentGameMode == GameModeServer)
[(ServerMultiplayerManager *)multiplayerManager sendNetworkPacket:data withTag:MultiPlayerTypeInfoNextRoundConfirm];
- (void)sendNetworkPacket:(NSData *)data withTag:(long)tag
{
[asyncSocket writeData:data withTimeout:-1 tag:tag];
}
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
{
NSLog(@"DID WRITE DATA tag is %ld", tag);
[sock readDataWithTimeout:-1 tag:0];
}
Run Code Online (Sandbox Code Playgroud)
我读了这样的数据:
- (void)socket:(GCDAsyncSocket *)sender didReadData:(NSData *)data withTag:(long)tag
{
NSString *receivedInfo = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
[info_data setData:data];
NSLog(@"DID READ DATA WITH TAG %ld", tag);
if ([receivedInfo isEqualToString:ROOM_FILLED])
{
isMaster = (tcpRequest.identifier == MASTER_CHAR);
NSLog(@"IS MASTER SET %d", isMaster);
[multiplayerDelegate setGameModeServer];
[multiplayerDelegate startGame];
}
else
[self dataProcessing:info_data];
[sender readDataWithTimeout:-1 tag:0];
}
- (void)dataProcessing:(NSData *)data
{
NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:data];
MultiPlayerTypeInfo typeInfo = [[dict objectForKey:@"type_info"] intValue];
}
Run Code Online (Sandbox Code Playgroud)
我的问题是这些数据包被弄乱了.假设在接收器设备处读取标记有标签10的分组作为标记为11的分组,该分组在分组10之后立即发送,并且当涉及到实际分组11的归档时NSKeyedUnarchiver抛出异常Incomprehensible archive.
据我所知,我应该以某种方式分离数据包.我尝试的是将分离符号附加到正在发送的数据:
[data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
Run Code Online (Sandbox Code Playgroud)
并试图像这样阅读:
[socket readDataToData:[GCDAsyncSocket CRLFData] timeout:-1 tag:some_tag];
Run Code Online (Sandbox Code Playgroud)
但它没有帮助.我做错了什么,我该怎么做?
我想,你误解了标签的作用.GCDAsyncSocket(顾名思义)是一个异步插座.标签可以帮助您将接收到的数据与接收订单匹配,并将发送成功与发送订单匹配.
例如,如果你想发送数据,你可以使用writeData:messageA withTimeout:-1 tag: tagA(或类似的东西)给你的套接字命令在不久的将来发送一些.现在不一定是这样.你可以立即给下一个订单发送另一条消息,比如messageB标签tagB.要知道,messageA真的发送了,你会收到通知socket:aSocket didWriteDataWithTag:aTag.在这里,aTag具有的价值tagA,如果messageA被发送,价值tagB,如果messageB被发送.标签不随消息一起发送; 它只能帮助您识别您的订单.
接收方也是如此.您给订单接收(某些)某些数据并为该订单分配标签.一旦你没有接收数据,通知(通过socket:didReadData:withTag:),说明你的标签,让你知道,这才能取得成功.
您可以将标记用于某些语义信息并将其放入您的消息中.但即使这样,通知中的标签也是接收订单的标签,但绝不是发送订单中的标签.如果要使用放在接收方的消息中的标记,则必须首先接收(至少部分)消息并解析它.
找出问题的核心:您基本上有两种可能性来了解,哪种数据到达:
编辑
以下是第二种方法的示例.假设你可以发送一些A,B等类的对象.你的标题可能包括你的数据的类型和大小:
typedef struct {
NSUInteger type_id;
NSUInteger size;
} header_t;
#define typeIdA 1
#define typeIdB 2
// ...
Run Code Online (Sandbox Code Playgroud)
一旦你想obj用objKey 发送一个对象:
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:obj forKey: objKey];
header_t head;
if ([obj class] == [A class]) {
head.type_id = typeIdA;
} else if ([obj class] == [B class]) {
head.type_id = typeIdB;
} else ...
// ....
header.size = data.lengh;
NSData* headData = [NSData dataWithBytes: &header length: sizeof(header)];
dataWithBytes:length:
header = NSData.length;
[asyncSocket writeData:headData withTimeout:-1 tag:headTag];
[asyncSocket writeData:data withTimeout:-1 tag:dataTag];
Run Code Online (Sandbox Code Playgroud)
如果需要,您可以收到有关成功发送或错误的通知,但我在此处跳过此处.在接收方,您首先需要一个标题:
[receiveSocket readDataToLength:sizeof(header_t) withTimeout:-1 tag:rcvHdrTag];
// rcvHdrTag must not match one of the typeIdX tags
Run Code Online (Sandbox Code Playgroud)
在socket:didReadData:withTag:你必须区分,如果你得到标题或遗骸(在这里开始接收遗体!)
- (void)socket:(GCDAsyncSocket *)aSocket didReadData:(NSData *)data withTag:(long)tag {
header_t head;
id obj;
id key;
switch (tag) {
case rcvHdrTag:
[data getBytes:&head length:sizeof(header)];
// now you know what to receive
[aSocket readDataToLength:header.size withTimeout:-1 tag:header.type];
return;
break; // I know, redundancy :-)
case typeIdA:
objKey = objKeyA; // whatever it is...
break;
case typeIdB:
objKey = objKeyB;
// ....
}
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
obj = [unarchiver decodeObjectForKey:objKey];
// store your object ...
}
Run Code Online (Sandbox Code Playgroud)
这不是最优雅的示例,它忽略了归档中的对象树和对象间依赖关系,但您应该明白这一点.
| 归档时间: |
|
| 查看次数: |
5449 次 |
| 最近记录: |