在这里主要讲的UDP的内容,其实主要最近一直和设备打交道,所以一直需要用到socket,UDP和TCP相比,优势是数据的传输效率,无需3次的握手,只管收发,但是传输的可靠性上和TCP比就差很远了。
当然了,组播和广播都是属于分发式的和TCP面向连接冲突,注意咯,这里只要说到组播或者广播就是UDP的哦,让我们看一段广播的代码吧!
AsyncUdpSocket *multicast =[[AsyncUdpSocketalloc]initWithDelegate:self];
[multicast bindToPort:BROADCASTPort error:&error];
BYTE* pDataBuf = malloc(PACKET_HEAD_LEN);
memset(pDataBuf, 0, PACKET_HEAD_LEN);
*(uint32 *)pDataBuf = 0xa3;
*(uint32 *)(pDataBuf + 1) = 1;
*(uint32 *)(pDataBuf + 16) = 2;
NSMutableData* pData = [[NSMutableData alloc] initWithBytesNoCopy:pDataBuf length:PACKET_HEAD_LEN];
[multicast enableBroadcast:YES error:&error];
[multicast sendData:pData toHost:@"255.255.255.255" port:BROADCASTPort withTimeout:-1 tag:1];
[multicast receiveWithTimeout:-1 tag:1];
看下广播的知识吧:
三种I P地址:单播地址、广播地址和多播地址。
广播和多播仅应用于 U D P,它们对需将报文同时传往多个接收者的应用来说十分重要。
单播(unicast): 帧仅发往单个目的主机,目的地址指明单个接收接口.
广播(broadcast): 一个主机要向网上的所有其他主机发送帧.
多播(multicast): 帧仅传送给属于多播组的多个主机.
首先了解一下主机对由信道传送过来帧的过滤过程:
1. 网卡查看由信道传送过来的帧,确定是否接收该帧,若接收后就将它传往设备驱动程序。通常网卡仅接收那些目的地址为网卡物理地址或广播地址的帧.对于以太网,当地址中最高字节的最低位设置为1时表示该地址是一个多播地址,用十六进制可表示为 0 1 : 0 0 : 0 0 : 0 0 : 0 0 : 0 0(以太网广播地址ff:ff:ff:ff:ff:ff可看作是以太网多播地址的特例)
2.如果网卡收到一个帧,这个帧将被传送给设备驱动程序(如果帧检验和错,网卡将丢弃该帧).设备驱动程序将进行另外的帧过滤。首先,帧类型中必须指定要使用的协议(I P、A R P等等)。其次,进行多播过滤来检测该主机是否属于多播地址说明的多播组.
3. 设备驱动程序随后将数据帧传送给下一层,比如,当帧类型指定为IP数据报时,就传往IP层。IP根据IP地址中的源地址和目的地址进行更多的过滤检测。如果正常,就将数据报传送给下一层(如TCP或UDP).
4. 每次UDP收到由IP传送来的数据报,就根据目的端口号,有时还有源端口号进行数据报过滤。如果当前没有进程使用该目的端口号,就丢弃该数据报并产生一个ICMP不可达报文(TCP根据它的端口号作相似的过滤)。如果UDP数据报存在检验和错,将被丢弃。
示意图如下:
根据上面的过程我们知道,使用广播的问题在于它增加了对广播数据不感兴趣主机的处理负荷。拿一个使用UDP广播应用作为例子。如果网内有50个主机,但仅有20个参与该应用,每次这20个主机中的一个发送UDP广播数据时,其余30个主机不得不处理这些广播数据报。一直到UDP层,收到的UDP广播数据报才会被丢弃。这30个主机丢弃U D P广播数据报是因为这些主机没有使用这个目的端口。
多播的出现减少了对应用不感兴趣主机的处理负荷。使用多播,主机可加入一个或多个多播组。这样,网卡将获悉该主机属于哪个多播组,然后仅接收主机所在多播组的那些多播帧。
受限的广播地址是 255. 255 . 255 . 255,需要注意的是:
在任何情况下,路由器都不转发目的地址为受限的广播地址的数据报,这样的数据报仅出现在本地网络中。
指向网络的广播地址是主机号为全1的地址。A类网络广播地址为netid . 255 . 255 . 255,其中netid为A类网络的网络号。一个路由器必须转发指向网络的广播,但它也必须有一个不进行转发的选择。
然后在回调种接收数据,这样就完成一个完整的广播。
- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{
NSString* result;
result = [[NSStringalloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(@"%@",result);
NSLog(@"received");
}
-(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error{
NSLog(@"not received");
}
-(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error{
NSLog(@"%@",error);
NSLog(@"not send");
}
-(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
NSLog(@"send");
}
-(BOOL)onUdpSocketDidClose:(AsyncUdpSocket *)sock{
NSLog(@"closed");
}