做项目的时候用到了GCDAsyncUdpSocket,所以在此总结下它的用法,作为笔记;
GCDAsyncUdpSocket开源类库是以苹果的GCD多任务处理机制完成的一个异步交互套接字通讯。如果需要使用同步的,则去寻找AsyncUdpSocket就可以了。该开源库完成了UDP之间的通信,使得UDP通信的编程变得更加简单;
源码在谷歌上一搜便有,下面给出github的地址:https://github.com/robbiehanson/CocoaAsyncSocket
下载即可。
该开源库里面也有相应地示例代码,但如果需要用到我们的代码里面,只需要复制出GCDAsyncUdpSocket.h,GCDAsyncUdpSocket.m文件到工程中就可以了。
首先,需要导入头文件,在需要引用GCDAsyncUdpSocket的地方(如我定义一个网络类UdpAssociation.m)的.h文件中导入GCDAsyncUdpSocket.h文件
如:
#import "GCDAsyncUdpSocket.h"
接着,在UdpAssociation的头文件里改成:
@interface UdpAssociation : NSObject <GCDAsyncUdpSocketDelegate>
代表着类UdpAssociation要遵守这个协议;
接着,在类UdpAssociation中定义一个GCDAsyncUdpSocket对象
如:
GCDAsyncUdpSocket *udpSocket;
在初始化函数中需要完成几个步骤:
·实例化一个GCDAsyncUdpSocket对象
如:
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
解释:
查看它的源代码,会发现还有好几种初始化的方法,这里选用的是其中的一种,initWithDelegate:self设置代理是自己,意味着自己会接受到与该协议相关的任何消息,delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);这里给delegateQueue加的是全局并发的队列,也可以给其它的队列;
·接着绑定通信端口
NSError *error = nil;
if(![udpSocket bindToPort :servicePort error:&error])
{
NSLog(@"error in bindToPort");
//return;
}
·到此所有初始化工作已经完成。
该开源库总共需要写6个代理函数:
可以查看协议头文件可得:
@protocol GCDAsyncUdpSocketDelegate
@optional
/**
* By design, UDP is a connectionless protocol, and connecting is not needed.
* However, you may optionally choose to connect to a particular host for reasons
* outlined in the documentation for the various connect methods listed above.
*
* This method is called if one of the connect methods are invoked, and the connection is successful.
**/
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address;
/**
* By design, UDP is a connectionless protocol, and connecting is not needed.
* However, you may optionally choose to connect to a particular host for reasons
* outlined in the documentation for the various connect methods listed above.
*
* This method is called if one of the connect methods are invoked, and the connection fails.
* This may happen, for example, if a domain name is given for the host and the domain name is unable to be resolved.
**/
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error;
/**
* Called when the datagram with the given tag has been sent.
**/
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
/**
* Called if an error occurs while trying to send a datagram.
* This could be due to a timeout, or something more serious such as the data being too large to fit in a sigle packet.
**/
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error;
/**
* Called when the socket has received the requested datagram.
**/
(void)udpSocket:(GCDAsyncUdpSocket *)sock
didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext;
/**
* Called when the socket is closed.
**/
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error;
@end
其中最重要的是写好接收的回调函数就可以了:
(void)udpSocket:(GCDAsyncUdpSocket *)sock
didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext;
data就是接收到得数据,在该函数写好具体的处理函数就好了。
·首先谈谈接收:
在初始化的最后加上下面接收这句,便开始接收了(一旦有数据发送过来)。
首先接收是异步的,所以对于大量数据同时发送的时候要注意接收的顺序问题;
接着,该开源库接收也有两种方法:
[udpSocket receiveOnce:&error];
[udpSocket beginReceiving:&error];
两种的区别是:[udpSocket receiveOnce:&error]只能接收一次数据,而在正常的UDP通信中是可不停地接收的,如果需要不停地接收那就适合使用第二条[udpSocket beginReceiving:&error];
但两者又有关联,两者是可以互相转化的,比如,在某种情况下,你需要只接受一次数据,那就可以先选用[udpSocket receiveOnce:&error];接下来在完成某件事情后,你需要开始正常的不停的接收了,这时候只需要再写一句:[udpSocket beginReceiving:&error];这样就能够转化了。
·发送
发送比较简答,只需要在需要发送数据的地方加上:
[udpSocket sendData:sendData toHost:serviceAddress port:servicePort withTimeout:-1 tag:tag];
看源码也会发现还有许多中发送的方法,具体可以去源码查看;
注意:这里的发送也是异步的。
withTimeout设置成-1代表超时时间为-1,即永不超时;
同时这里的tag也可以作为一个标签使用,具体用法可以参考以下博文:
《GCDAsyncSocket类库,IOS下TCP通讯使用心得》
好了,到此,你应该能够利用该开源库进行基本的通信了!