相關(guān)概念:
單播、多播(組播)和廣播的區(qū)別? http://blog.csdn.net/wangerge/article/details/3931491
多播(組播)地址范圍--224.0.0.0到239.255.255.255
廣播地址: 255.255.255.255
應(yīng)用場景:
家庭局域網(wǎng)設(shè)備組件一個局域網(wǎng),各設(shè)備提供udp socket監(jiān)聽服務(wù),手機(jī)客戶端進(jìn)入此局域網(wǎng),并向局域網(wǎng)內(nèi)發(fā)送組播或廣播,對應(yīng)設(shè)備響應(yīng)組播并按需要與手機(jī)端建立tcp長連接通信
1.服務(wù)端:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
GCDAsyncUdpSocket *serverSocket = [[[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()] autorelease];
NSError *bindError = nil;
//bindToPort綁定端口函數(shù),只能使用在充當(dāng)server 的socket上 client socket不能使用
//[serverSocket bindToPort:8099 interface:@"en1" error:&bindError]; //en1 隨機(jī)分配的ip地址
[serverSocket bindToPort:8099 error:&bindError]; //該socket默認(rèn)綁定到該機(jī)子網(wǎng)卡的ip地址
if (bindError) {
NSLog(@"bindError = %@",bindError);
}
NSError *receiveError = nil;
[serverSocket beginReceiving:&receiveError]; //開始接收數(shù)據(jù),一定要否則后面無法接收數(shù)據(jù) 不接收數(shù)據(jù)時調(diào)用pauseReceiving
if (receiveError) {
NSLog(@"receiveError = %@",receiveError);
}
//[serverSocket joinMulticastGroup:@"224.0.1.23" error:nil];//該socket加入到組播224.0.1.23中,之后只要客戶端socket向這個組播地址發(fā)消息,該socket都能收到 與客戶端的發(fā)送地址必須一致才能接收
NSLog(@"%@",[serverSocket localHost]);
///////////////////////////服務(wù)開啟時同時開啟TCP服務(wù)監(jiān)聽,以便后面建立TCP連接
GCDAsyncSocket *socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
NSError *err = nil;
if(![socket acceptOnPort:8099 error:&err])//tcp socket的監(jiān)聽端口必須要與udp socket的端口一樣 后面客戶端才能正確與服務(wù)端建立tcp連接,因為客戶端到時獲取的端口是udp socket的端口
{
NSLog(@"err.description = %@",err.description);
}else
{
NSLog(@"%@",[NSString stringWithFormat:@"開始監(jiān)聽%d端口.",8099]);
}
/////////////////////////////
}
udpsocket的關(guān)鍵回調(diào)方法:接收到客戶端socket發(fā)送的消息響應(yīng)如下
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext {
NSLog(@"sock = %@, ReceiveData = %@, fromAddress = %@",sock,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding],[[NSString alloc] initWithData:address encoding:NSUTF8StringEncoding]);
NSString *responseMessage = @"已即受到";
NSString *host = nil;
uint16_t port = 0;
[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];//可獲取客戶端socket的ip和端口,不過直接打印address是空的
NSLog(@"Adress = %@ %i",host,port);
[sock sendData:[responseMessage dataUsingEncoding:NSUTF8StringEncoding] toAddress:address withTimeout:-1 tag:10];//服務(wù)端回應(yīng)客戶端
}
Tcp socket關(guān)鍵回調(diào)方法
- (void)socket:(GCDAsyncSocket *)sender didAcceptNewSocket:(GCDAsyncSocket *)newSocket
{
NSLog(@"%@",[NSString stringWithFormat:@"建立與%@的連接",newSocket.connectedHost]);
s = newSocket;
s.delegate = self;
[s readDataWithTimeout:-1 tag:0];//必須調(diào)用
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *receive = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",[NSString stringWithFormat:@"%@:%@",sock.connectedHost,receive]);
NSString *reply = [NSString stringWithFormat:@"收到:%@",receive];
[s writeData:[reply dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
[s readDataWithTimeout:-1 tag:0];
}
2.客戶端:
- (IBAction)broadCast:(id)sender {
GCDAsyncUdpSocket *udpSocket = [[[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()] autorelease];
NSError *error = nil;
[udpSocket enableBroadcast:YES error:&error];//允許廣播 必須 否則后面無法發(fā)送組播和廣播
NSString *message = @"ttt";
//[udpSocket sendData:[message dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:10];//該函數(shù)只能用戶已經(jīng)連接的socket
[udpSocket sendData:[message dataUsingEncoding:NSUTF8StringEncoding] toHost:@"224.0.1.23"? port:8099 withTimeout:-1 tag:10];//客戶端socket發(fā)送組播或是廣播 根據(jù)host的ip地址來訂
[udpSocket beginReceiving:nil];//必須要? 開始準(zhǔn)備接收數(shù)據(jù)
}
UDP 回調(diào)函數(shù)
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext {
NSLog(@"ReceiveData = %@, fromAddress = %@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding],[[NSString alloc] initWithData:address encoding:NSUTF8StringEncoding]);
NSString *host = nil;
uint16_t port = 0;
[GCDAsyncUdpSocket getHost:&host port:&port fromAddress:address];//從此可以獲取服務(wù)端回應(yīng)的ip和端口 用于后面的tcp連接
NSLog(@"Adress = %@ %i",host,port);
//開啟tcp連接
sockeTCP = [[GCDAsyncSocket alloc]initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
//socket.delegate = self;
NSError *err = nil;
if(![sockeTCP connectToHost:host onPort:port error:&err])
{
}else
{
NSLog(@"tcp ok");
[sockeTCP writeData:[@"發(fā)送tcp消息" dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:0];
[sockeTCP readDataWithTimeout:-1 tag:0];
}
}
TCP 回調(diào)函數(shù):
-(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
NSLog(@"%@",[NSString stringWithFormat:@"tcp連接到:%@",host]);
[sockeTCP readDataWithTimeout:-1 tag:0];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString *newMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"tcp newMessage = %@",newMessage);
}