gpt4 book ai didi

objective-c - 使用GCDASyncSocket时如何分离数据包

转载 作者:可可西里 更新时间:2023-11-01 02:35:09 25 4
gpt4 key购买 nike

谁能帮帮我?我使用 GCDAsyncSocket 通过 TCP 协议(protocol)在两个设备之间密集交换数据。我发送这样的数据:

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

我这样读取数据:

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

我的问题是这些数据包被弄乱了。假设标有标签 10 的数据包在接收设备上被读取为标有标签 11 的数据包,它是在数据包 10 之后立即发送的,当涉及到实际数据包 11 的解压缩时 NSKeyedUnarchiver 抛出异常 难以理解的存档

据我所知,我应该以某种方式将数据包分开。我尝试的是将分隔符号附加到正在发送的数据中:

[data appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];

并尝试像这样阅读它:

[socket readDataToData:[GCDAsyncSocket CRLFData] timeout:-1 tag:some_tag];

但这并没有帮助。我做错了什么,我应该怎么做?

最佳答案

我想,您误解了标签的作用。 GCDAsyncSocket(顾名思义)是一个异步套接字。该标签可帮助您将接收到的数据与接收订单相匹配,发送成功与发送订单相匹配,分别。

例如,如果你想发送数据,你可以使用 writeData:messageA withTimeout:-1 tag: tagA (或类似的东西)给你的套接字发送命令 somewhen in the不久的将来。现在不一定是。您可以立即发出下一个命令以发送另一条消息,例如带有标签tagBmessageB。要知道 messageA 确实已发送,您可以通过 socket:aSocket didWriteDataWithTag:aTag 收到通知。此处,如果 messageA 被发送,aTag 的值为 tagA,如果 则为 tagB messageB 已发送。标记与消息一起发送;它只会帮助您识别您的订单。

在接收端也是一样的。您下达命令(有时)接收一些数据并为该订单分配一个标签。一旦您确实收到数据,通知(通过socket:didReadData:withTag:)会显示标签,让您知道哪个订单成功。

您可以将标签用于某些语义信息并将其放入您的消息中。但即便如此,通知中的标签是接收订单的标签,而不是发送订单的标签。如果你想在接收方使用你在消息中放置的标签,你必须先接收(至少部分)消息并解析它。

来到问题的核心:您基本上有两种可能知道哪种数据正在到达:

  1. 了解发送数据的顺序并以完全相同的顺序接收它。
  2. 使用标识数据类型的消息头。仅接收头部,并根据头部数据接收和解析消息的剩余部分。

编辑

这是第二种方法的示例。假设您可以发送多个 A、B 等类的对象。您的 header 可能包含数据的类型和大小:

      typedef struct {
NSUInteger type_id;
NSUInteger size;
} header_t;

#define typeIdA 1
#define typeIdB 2
// ...

一旦你想用objKey发送一个对象obj:

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

如果需要,您可以获得有关成功发送或错误的通知,但我在此跳过。在接收方,您首先需要一个 header :

    [receiveSocket readDataToLength:sizeof(header_t) withTimeout:-1 tag:rcvHdrTag];
// rcvHdrTag must not match one of the typeIdX tags

在你的socket:didReadData:withTag:中你必须区分,你是得到header还是remains(remains的接收在这里开始!)

   - (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 ...
}

这不是最优雅的示例,它忽略了归档中的对象树和对象间依赖关系,但您应该明白这一点。

关于objective-c - 使用GCDASyncSocket时如何分离数据包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11833551/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com