iOS --- UDP
2018-11-06 本文已影响0人
BabyNeedCare
想起西游记里的一个场景:
孙悟空拿了真的葫芦,问银角大王,我叫你名字,你敢答应吗?银角大王应答了,结果,悲催的被吸走了。
UDP协议广播机制:
原理一样。在人群叫喊(广播)银角大王。银角大王应答。抓的就是你,哈哈!!!
UDP广播机制的应用场景:
例如:iPhone手机连接设备,例如手环。
-
100个iPhone同时叫喊(广播)手环,手环应答,某一台iPhone设备就连接,然后进入长连接(如果有同学问为啥是长连接,不是长连接难不成一连接就断开?)
-
手环监听人体运动信息,iPhone连接后,就可以通过发送指令获取已经存储的信息 / 写入消息,展示在iPhone UI上
AsyncSocket流程有4步:
1.创建socket,修改配置(允许广播形式)
+(Singleton *)sharedInstance{
static Singleton *sharedInstace = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstace = [[self alloc]init];
});
return sharedInstace;
}//一个客户端只进行一条socket的连接,所以这里使用了单例。
self.socket = [[AsyncUdpSocket alloc]initWithDelegate:self]; //创建socket(UDP)
[self.socket enableBroadcast:YES error:nil]; //允许广播形式
2.绑定本地IP
self.localhost = [self getIPAddress];
NSError *error = nil;
[self.socket bindToAddress:self.localhost port:0 error:&error]; //绑定本地IP与端口
-(NSString *)getIPAddress{
NSString *address = @"error";
struct ifaddrs *interface = NULL;
struct ifaddrs *temp_addr = NULL;
int success = 0;
success = getifaddrs(&interface);
if(success == 0){
temp_addr = interface;
while (temp_addr != NULL) {
if(temp_addr->ifa_addr->sa_family == AF_INET){
//if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]){
address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
// }
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interface);
return address;
}//本地IP的获取方法
3.向服务器发送包
-(void)longConnectToSocket{
NSData *dataStream = [message dataUsingEncoding:NSUTF8StringEncoding];
[self.socket sendData:dataStream
toHost:@"x.x.x.x"
port:YourPort
withTimeout:-1
tag:0];
}//端口是固定的, ip嵌入式提供
4.接收包
-(void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
[self.socket receiveWithTimeout:-1 tag:tag];
}
-(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{
do some thing about data
return YES;
}
用得比较多的可能是GCDAsyncUdpSocket。
处理方式与AsyncSocket大致相同。
-
import "GCDAsyncUdpSocket.h"
- 遵守协议<GCDAsyncUdpSocketDelegate>
- 声明一个属性@property (strong, nonatomic)GCDAsyncUdpSocket * udpSocket;
- 创建Socket
_udpSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
5.监听接口&接收数据
NSError * error = nil;
[_udpSocket bindToPort:udpPort error:&error];
if (error) {//监听错误打印错误信息
NSLog(@"error:%@",error);
}else {//监听成功则开始接收信息
[_udpSocket beginReceiving:&error];
}
- 发送数据
[_udpSocket sendData:sendData toHost:ipAddress port:udpPort withTimeout:-1 tag:0];
- GCDAsyncUdpSocket代理方法
//看看发送数据结果
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag{
NSLog(@"发送信息成功");
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error{
NSLog(@"发送信息失败");
}
//发送成功就该接收数据了
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext{
NSLog(@"接收到%@的消息:%@",address,data);//自行转换格式吧
}
接收信息有两种方法:
1.[_udpSocket receiveOnce:&error]此方法是一条一条数据接收,用途往往是先发广播,接收到信息后使用TCP进行长连接,故只接收一条数据即可。
2.[_udpSocket beginReceiving:&error]此方法是持续接收,像微信是,自然是要持续接收信息,故使用此方法进行接收数据。