智能冲秽,這個(gè)名詞越來(lái)越多的被應(yīng)用到生活中。智能手機(jī)矩父、智能電視劳跃、智能手表。浙垫。刨仑。電視有電視遙控器郑诺,空調(diào)有空調(diào)遙控器,按摩器有按摩器遙控器杉武。辙诞。。各種產(chǎn)品都有各自的一套遙控管理系統(tǒng)。《人生遙控器》中的邁可·紐曼在各種遙控器中總也找不到正確的遙控器硫豆,渴望有一個(gè)萬(wàn)能遙控器橙依。在現(xiàn)實(shí)生活中是否也能有這樣的遙控器呢臣樱,怎么實(shí)現(xiàn)呢?
我們生活中用到的最多的智能產(chǎn)品應(yīng)該是手機(jī)了,把手機(jī)和其它智能產(chǎn)品聯(lián)系起來(lái)是個(gè)不錯(cuò)的選擇。那么怎么實(shí)現(xiàn)呢梁呈?有2種方式供選擇,一個(gè)是藍(lán)牙蘸秘,一個(gè)是建立socket連接官卡。今天我們討論的是建立socket連接。
案例:利用手機(jī)對(duì)電視進(jìn)行遙控
? ? **實(shí)現(xiàn)方案:1.在電視端搭建sever醋虏;2.在手機(jī)端搭建client寻咒;3.手機(jī)端發(fā)送UDP廣播;4.電視端收到廣播后回包颈嚼,回包信息包括TCP端口和其它配置信息毛秘;5.手機(jī)端通過(guò)服務(wù)端回包中的端口號(hào)向服務(wù)端發(fā)起TCP連接;6.發(fā)送指令阻课,實(shí)現(xiàn)對(duì)電視的遙控熔脂。
? ? **開(kāi)發(fā)工具:Xcode9.2
? ? **框架:GCDAsyncSocket框架,下載地址:https://github.com/robbiehanson/CocoaAsyncSocket柑肴,下載后資源文件路徑:../Source/GCD,把GCD文件夾下的GCDAsyncSocket.h旬薯、GCDAsyncSocket.m晰骑、GCDAsyncUdpSocket.h、GCDAsyncUdpSocket.m 這4個(gè)文件拖入項(xiàng)目中绊序。其中GCDAsyncSocket是對(duì)TCP套接字的封裝硕舆,GCDAsyncUdpSocket是對(duì)UDP套接字的封裝。
具體實(shí)現(xiàn):
UDP
一骤公、UDP服務(wù)端
? ? 1.監(jiān)聽(tīng)端口:
- (BOOL)bindToPort:(uint16_t)port error:(NSError **)errPtr;
????2.代理方法:
// 當(dāng)收到UDP包時(shí)抚官,會(huì)調(diào)用這個(gè)方法
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext;
// 成功發(fā)送UDP包時(shí)調(diào)用的方法阶捆,服務(wù)端和客戶(hù)端通用
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag;
// 發(fā)送UDP包失敗時(shí)調(diào)用的方法凌节,服務(wù)端和客戶(hù)端通用
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error;
// 連接斷了之后調(diào)用的方法钦听,服務(wù)端和客戶(hù)端通用
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error;
????3.向客服端發(fā)送回包:
// 服務(wù)端和客戶(hù)端通用
- (void)sendData:(NSData *)data toAddress:(NSData *)remoteAddr withTimeout:(NSTimeInterval)timeout tag:(long)tag;
二、UDP客戶(hù)端
? ? 1.發(fā)送廣播:
? ? ? ? -- host :不知道IP時(shí)傳廣播地址:255.255.255.255
- (void)sendData:(NSData *)data toHost:(NSString *)host port:(uint16_t)port withTimeout:(NSTimeInterval)timeout tag:(long)tag;
? ? 2.代理方法同上倍奢。
三朴上、TCP服務(wù)端
? ? 1.監(jiān)聽(tīng)端口:
// 返回值為 YES 時(shí)表示監(jiān)聽(tīng)成功,并不代表成功與客戶(hù)端建立連接
- (BOOL)acceptOnPort:(uint16_t)port error:(NSError **)errPtr;
? ? 2.代理方法:
// 與客戶(hù)端成功建立連接后調(diào)用此方法卒煞。
- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket;
// 收到消息時(shí)調(diào)用痪宰,服務(wù)端和客服端通用
- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
四、TCP客戶(hù)端
? ? 1.連接服務(wù)端:
//?timeout 傳-1表示不設(shè)置超時(shí)限制畔裕,如果需要設(shè)置傳其它非負(fù)正整數(shù)值衣撬,??返回 YES 不表示已經(jīng)與服務(wù)端連接成功
- (BOOL)connectToHost:(NSString *)host onPort:(uint16_t)port ?withTimeout:(NSTimeInterval)timeout error:(NSError **)errPtr;
? ? **2.連接成功后,開(kāi)始接收數(shù)據(jù):
// 在收到連接成功的代理方法中調(diào)用該方法扮饶。
- (void)readDataWithTimeout:(NSTimeInterval)timeout tag:(long)tag;
????3.發(fā)送數(shù)據(jù):
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;
? ? 4.斷開(kāi)連接:
- (void)disconnect;
????5.代理方法:
// 與服務(wù)端連接成功具练,在這個(gè)方法中調(diào)用 **2 中提到的方法
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port;
// 發(fā)送數(shù)據(jù)成功后調(diào)用的方法贴届,服務(wù)端和客戶(hù)端通用
- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag;
// 連接失敗時(shí)調(diào)用該方法
- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err;
以上是GCDAsyncSocket框架建立socket連接的最基本的方法靠粪,詳情可參照Demo, 密碼:xjl0。
小彩蛋:
1. int 轉(zhuǎn) byte :
// ?有高位和地位之分毫蚓,如果不符合需求占键,把0-4位的位移按倒序?qū)懠纯伞?/p>
????NSInteger Id = 10; ? ?
????Byte bytes[4];
????bytes[0] = (Byte)(Id);
? ? bytes[1] = (Byte)(Id>>8);
????bytes[2] = (Byte)(Id>>16);
????bytes[3] = (Byte)(Id>>24);
2.拼接 Byte 和 NSData?
// 把 Byte 轉(zhuǎn)換成 NSData,再用NSMutableData 拼接元潘∨弦遥或按照下面代碼的方式,直接發(fā)byte 轉(zhuǎn)成?NSMutableData 翩概,再拼接 data牲距。
NSMutableData *newData = [[NSMutableData alloc] initWithBytes:bytes length:sizeof(bytes)];
?[newData appendData:data];