我是网络编程新手,基本上是边做边学。我正在跟随 iPhone酷项目的Mike Ashes程序“Sphere Net”。我理解程序中发生了什么,但是我已经准备好开始扩展它了,我期望发送一种合理的各种数据包类型(每种都表示为结构)。为每种类型的数据包声明不同的方法似乎并不严格。
如果我正在处理objective-c类,我会让函数将超类作为参数,或者使用id。但由于我使用的是按价值结构,我认为我不能使用这种策略。
我要求指向一个很好的参考指针,解释一个典型的程序如何处理各种各样的数据包(struct)类型,无论是书籍,链接还是堆栈溢出答案。
(翻译:我不想写几个完全相同的新方法,除了每次我决定添加新类型数据包时它们处理的数据包类型)
作为参考,Sphere Net类型程序的基本概要在标题中:
typedef struct {
uint32_t identifier;
uint32_t datatype;
} PacketHeader;
typedef struct {
PacketHeader header;
int32_t dataItem1;
int32_t dataItem2;
} MyPacket;
static const uint32_t kPacketIdentifier = 'pkt';
在实施中:
-(void) init{
// do all the setup, open the sockets, start bonjour.
// start the listener thread
[NSThread detachNewThreadSelector:@selector(listenThread) toTarget:self withObject:nil];
}
- (void)objectOfInterestChanged:(ObjectOfInterest *)interestingObject {
PositionPacket packet;
packet.dataItem1 = CFSwapInt32HostToBig(round(interestingObject.someFloat));
packet.dataItem2 = CFSwapInt32HostToBig(round(interestingObject.someFloat));
[self sendUpdatePacket:packet];
}
- (void)sendUpdatePacket:(MyPacket)packet{
packet.header.identifier = CFSwapInt32HostToBig(kPacketIdentifier);
packet.header.datatype = CFSwapInt32HostToBig(kPacketType);
for(NSNetService *service in _services)
for(NSData *address in [service addresses])
sendto(_socket, &packet, sizeof(packet), 0, [address bytes], [address length]);
}
- (void)listenThread {
while(1)
{
MyPacket packet;
struct sockaddr addr;
socklen_t socklen = sizeof(addr);
ssize_t len = recvfrom(_socket, &packet, sizeof(packet), 0, &addr, &socklen);
if(len != sizeof(packet))
continue;
if(CFSwapInt32BigToHost(packet.basePacket.header.identifier) != kPacketIdentifier)
continue;
//if(CFSwapInt32BigToHost(packet.basePacket.header.datatype) != kPacketType)
// continue;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSData *packetData = [NSData dataWithBytes:&packet length:sizeof(packet)];
NSData *addressData = [NSData dataWithBytes:&addr length:socklen];
NSArray *arguments = [NSArray arrayWithObjects:packetData, addressData, nil];
//SEL mainThreadSEL = @selector(mainThreadReceivedPositionPacket:);
SEL mainThreadSEL;
if(CFSwapInt32BigToHost(packet.basePacket.header.datatype) == kPacketType)
mainThreadSEL = @selector(mainThreadReceivedPacket:);
[self performSelectorOnMainThread:mainThreadSEL withObject:arguments waitUntilDone:YES];
[pool release];
}
}
- (void)mainThreadReceivedPacket:(NSArray *)arguments {
// extract the objects from the array created above
NSData *packetData = [arguments objectAtIndex:0];
NSData *addressData = [arguments objectAtIndex:1];
const MyPacket *packet = [packetData bytes];
// ...accounting for differences in endianness
int32_t x = CFSwapInt32BigToHost(packet->dataItem1);
int32_t y = CFSwapInt32BigToHost(packet->dataItem2);
AnObject *update;
update.interestingUpdate = CGThingMake(x, y);
[delegate networkController:self didReceiveUpdate:update fromAddress:addressData];
}
答案 0 :(得分:0)
经过一番研究后,我拿到了一个解决方案。它基本上是这样的:
使用特定信息创建特定数据包 创建一个“传输”数据包,其结构如下:
typedef struct TransmissionStruct{
size_t typeOfPacketIdentifier;
char arrayOfBytesHoldingSpecificStruct [<sizeoflargeststruct>]
} Transmission Struct
然后使用memcopy(const void*, const void*, size);
复制transimssion结构的char数组中特定结构的数据。
然后在接收端,你知道你收到的任何字节的第一个字节将是类型标识符,所以读取前四个字节,然后从那里你可以决定如何处理其余的字节
这方面的一个例子是: iphone problem receiving UDP packets