UDP接收消息案例
UDP 的特性就是效率高 速度快 但是准确率无法保障 正常情况就是发送
这里继续以CocoaAsyncSocket 这个库为例 首先导入库对应的头文件以及继承下相关的代理 然后我们要知道监听的对端的ip和端口号 这里以ip:192.168.0.100 端口号: 8000为案例
#define BOARD_CAST_PORT 8000 // 监听广播的端口
#define BOARD_CAST_ADDRESS @"192.168.0.100" // 监听广播的ip地址
#define UDP_MAX_SEND_FAILED_COUNT 20 // 最大尝试次数
#import <CocoaAsyncSocket/GCDAsyncUdpSocket.h>
@interface UDPServerSocket : NSObject<GCDAsyncUdpSocketDelegate>
@property (nonatomic, weak) id <UDPServerSocketDelegate>delegate;
@property (nonatomic, strong) GCDAsyncUdpSocket * udpSocket;
@property (nonatomic, copy) NSString * clientIP;
@property (nonatomic, assign) uint16_t clientPort;
@property (nonatomic, assign) BOOL isSending;
@property (nonatomic, strong) NSMutableArray * messageQueue;
@property (nonatomic, copy) NSString * currentSendingMessage;
@property (nonatomic, assign) NSInteger times;
@property (nonatomic, assign) NSInteger resendTimes;开启UDP
// 开启UDP
- (void)startConnectUdpSocket {
[self disConnect];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
self.udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:queue];
self.isOpen = YES;
self.sendFailedCount = 0;
self.sendCount = 0;
// 开启广播
[self startReceiveBroadcast];
}停止UDP
// 停止
- (void)disConnect {
if (self.udpSocket) {
[self.udpSocket close];
}
self.isOpen = NO;
self.sendCount = 0;
NSLog(@"udpsocket关闭了");
}这里开启接收广播的时候 需要先绑定下监听的端口号 另外需要允许接收广播(也就是开启对应权限)
- (void)startReceiveBroadcast {
NSLog(@"startReceiveBroadcast udp server");
NSError *error = nil;
if (![self.udpSocket bindToPort:BOARD_CAST_PORT error:&error]) {
NSLog(@"bindToPort 绑定端口出现错误");
return;
}
if (![self.udpSocket enableBroadcast:YES error:&error]) {
NSLog(@"udpSocket 允许广播出现错误");
return;
}
// 对端ip
NSString *tmpAddress = BOARD_CAST_ADDRESS;
// 关键一行代码,发送广播,即使应用不需要。如果不发送,无法触发是否允许访问本地网络弹框。
[self sendData:[@{} mj_JSONData] withAddress:tmpAddress onPort:BOARD_CAST_PORT];
NSError *receiveError = nil;
if (![self.udpSocket beginReceiving:&receiveError]) {
NSLog(@"beginReceiving开始接受数据出现错误");
return;
}
}UDP的广播方法代理
#define mark - GCDAsyncUdpSocketDelegate
- (void)sendData:(NSData *)data withAddress:(NSString *)address onPort:(UInt16)port {
if (!self.isOpen) {
NSLog(@"udp关闭了");
return;
}
[self.udpSocket sendData:data toHost:address port:port withTimeout:UDP_TIME_OUT tag:HOMEVISION_BROADCAST_TAG];
}
// 连接成功
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address {
NSLog(@"didConnectToAddress");
}
// 连接断开
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error {
NSLog(@"didNotConnect");
}
// 通过tag发送消息
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag {
self.sendFailedCount = NUMBER_ZERO;
NSLog(@"didSendDataWithTag");
}为了防止 一直发送或者接收消息 这里给一个最大的尝试次数 超过之后 就直接断开连接
// 发送消息失败的回调
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error {
self.sendFailedCount++;
if (self.sendFailedCount >= UDP_MAX_SEND_FAILED_COUNT) {
NSLog(@"发送失败,次数超过 %ld了",UDP_MAX_SEND_FAILED_COUNT);
// 手动关闭连接
[self disConnect];
}
if (tag == HOMEVISION_BROADCAST_TAG) {
NSLog(@"发送数据失败");
}
}// upd连接关闭
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error {
NSLog(@"udpSocketDidClose %@",error.localizedDescription);
}
// upd接收到消息
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext {
if (address.length == NUMBER_ZERO) {
NSLog(@"接受的数据地址为空");
return;
}
NSString *hostAddress = [GCDAsyncUdpSocket hostFromAddress:address];
uint16_t port = [GCDAsyncUdpSocket portFromAddress:address];
// 判断是否为需要接收广播的设备ip
if ([hostAddress isEqualToString:BOARD_CAST_ADDRESS] && (port == HD_BOARD_CAST_PORT)) {
if (data.length == NUMBER_ZERO) {
NSLog(@"接收的数据为空");
return;
}
int messageCode = *(int *)([data bytes]);
NSString *addressString = [NSString stringWithFormat:@"receive data from hostaddress is %@ port is %hu",hostAddress,port];
NSLog(@"接收数据的地址为 %@",addressString);
}
}UDP的整体发送消息流程比较简单 不过开发者需要申请对应的的权限还是比较麻烦
我会单独出一期关于权限申请的流程。
本文是原创文章,完整转载请注明来自 MrXiao's Blog
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果