? ? ? ?最近工作中使用別人的SDK時(shí)看到了AsyncSocket這個(gè)類 簡(jiǎn)單查看了這個(gè)類的用處署海,發(fā)現(xiàn)是iOS socket套接字的封裝 用于iOS的socket編程吗购,上學(xué)時(shí)曾學(xué)到Linux的socket編程都是C函數(shù),上學(xué)時(shí)不用功(慚愧)砸狞,對(duì)socket算是聽說過捻勉,于是有些興趣再學(xué)習(xí)學(xué)習(xí)。
我使用socket編程 用到的通信協(xié)議有TCP和UDP刀森。 TCP是可傳輸控制協(xié)議踱启,它的傳輸是可靠的,需要三次握手建立連接研底, 四次握手釋放鏈接(具體怎么過程就不多說了)埠偿,UDP是用戶數(shù)據(jù)報(bào)協(xié)議 傳輸是不可靠地。
下載AsyncSockethttps://github.com/robbiehanson/CocoaAsyncSocket類庫(kù)榜晦,將RunLoop文件夾下的AsyncSocket.h, AsyncSocket.m, AsyncUdpSocket.h, AsyncUdpSocket.m 文件拷貝到自己的project中
添加CFNetwork.framework, 在使用socket的文件頭
一冠蒋、UDP:
AsyncUdpSocket類是支持UDP協(xié)議的socket編程類,使用也很容易乾胶,通信的收發(fā)過程都有代理可以調(diào)用抖剿。
self.udpSocket =[[AsyncUdpSocket alloc]initWithDelegate:self];//初始化socket,設(shè)置代理為self
self.portTF.text = @"8888";
NSError *error;
[self.udpSocket enableBroadcast:YES error:&error];//設(shè)置允許socket廣播识窿,如果不設(shè)置斩郎,則不能發(fā)消息
BOOL isBind = [self.udpSocket bindToPort:[self.portTF.text intValue] error:&error];//綁定一個(gè)未用的端口,我設(shè)置的是8888? 初始化一個(gè)socket只能綁定一次喻频,多次綁定直接崩 重新綁定得先調(diào)用[self.udpSocket close];然后重新生成一個(gè)socket再綁定缩宜。
接收數(shù)據(jù):
[self.udpSocket receiveWithTimeout:-1 tag:0];//接收數(shù)據(jù)的方法,調(diào)用一次就只接受一次發(fā)送的數(shù)據(jù)包甥温,設(shè)置timeout為-1就是永不超時(shí) 只要向該socket發(fā)送數(shù)據(jù)就能接收到脓恕,接收到數(shù)據(jù)后會(huì)調(diào)用- (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port 這個(gè)代理方法膜宋,所接受的數(shù)據(jù)也在該代理方法的data參數(shù)里窿侈, 上面接受方法里設(shè)置的tag值是幾炼幔,這代理方法的接收到tag值就是幾。host就是發(fā)消息的那個(gè)socket的主機(jī)地址史简。port是上面綁定的端口號(hào)(即8888乃秀,也是發(fā)送消息的socket的端口號(hào))。
這里如果設(shè)置的timeout不是-1圆兵,當(dāng)時(shí)間到后超時(shí)會(huì)調(diào)用代理-(void)onUdpSocket:(AsyncUdpSocket *)sock didNotReceiveDataWithTag:(long)tag dueToError:(NSError *)error
發(fā)送數(shù)據(jù):
NSString *str = self.sendTFV.text;
NSData *data=[str dataUsingEncoding:NSUTF8StringEncoding];
[self.udpSocket sendData:data toHost:self.serverHost port:[self.portTF.text intValue] withTimeout:5 tag:0];//這是發(fā)送的方法? 發(fā)送完后會(huì)調(diào)用代理-(void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag 這里的tag值與發(fā)送時(shí)設(shè)置的tag一致
這里自己測(cè)試時(shí)寫了自己的小程序玩玩socket udp通信程序 ?鏈接: https://pan.baidu.com/s/1SxpfWDq9yCOxELpegr_Jtg?提取碼: yq8q?
demo里有一個(gè)server程序跺讯、一個(gè)client程序。一個(gè)server程序可以用來廣播搜索同一網(wǎng)段內(nèi)的client設(shè)備殉农,玩的時(shí)候可以找三臺(tái)設(shè)備(我用的是一個(gè)iPad刀脏,兩個(gè)iPod,iPad裝server程序超凳,兩個(gè)iPod裝client程序愈污,iPad廣播搜索后會(huì)將兩個(gè)iPod的IP顯示出來,在iPad上選擇一/兩個(gè)IP 發(fā)送數(shù)據(jù)轮傍,相應(yīng)的一/兩個(gè)iPod會(huì)收到數(shù)據(jù))暂雹。
二、TCP
實(shí)現(xiàn)tcp協(xié)議需要一個(gè)服務(wù)器一個(gè)客戶端创夜,他們之間發(fā)送消息時(shí)需要先建立一個(gè)連接杭跪,然后才能收發(fā)數(shù)據(jù)。使用的類AsyncScoket驰吓。
服務(wù)器端:
self.tcpScoket = [[AsyncSocket alloc]initWithDelegate:self];//初始化 設(shè)置代理
NSError *error;
[self.tcpScoket acceptOnPort:8888 error:&error];//這個(gè)方法是監(jiān)聽8888端口號(hào)涧尿,接收通過8888端口號(hào)發(fā)來的連接請(qǐng)求。收到連接后會(huì)走代理- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket 在這個(gè)代理方法里 需要使用一個(gè)數(shù)組保存連接的socket檬贰,保證此鏈接是長(zhǎng)連接姑廉,如果不保存,則連接完后就會(huì)自動(dòng)斷開偎蘸,從而導(dǎo)致無(wú)法互相發(fā)收消息庄蹋;例如(我的demo里):在該方法中使用[self.clientSocketMuArr addObject:newSocket];保存此socket。使用[newSocket readDataWithTimeout:-1 tag:0];接收接下來客戶端可能發(fā)送的消息迷雪。
接下來會(huì)走代理方法:-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port 該方法中host就是連接的客戶端的IP
發(fā)送數(shù)據(jù):
NSData *data = [self.responseTF.text dataUsingEncoding:NSUTF8StringEncoding];
[self.tcpScoket writeData:data withTimeout:-1 tag:0];這個(gè)是發(fā)送數(shù)據(jù)的方法限书,與udp的發(fā)送方法名是不同的,但其功能與UDP的類似章咧,一次只發(fā)一個(gè)數(shù)據(jù)倦西。timeout設(shè)為-1也是永不超時(shí) 調(diào)用完之后也有代理方法觸發(fā)-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
接收數(shù)據(jù):
[sock readDataWithTimeout:-1 tag:0];方法名與UDP不同功能上也是類似的 一次只接受一個(gè)數(shù)據(jù),不調(diào)用就不會(huì)收到消息赁严,調(diào)用之后觸發(fā)代理- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
客戶端:
同樣的self.tcpScoket = [[AsyncSocket alloc]initWithDelegate:self];//初始化 設(shè)置代理
NSError *error;
BOOL isConnect = [self.tcpScoket connectToHost:@“192.168.3.105” onPort:8888 withTimeout:-1 error:&error];連接服務(wù)器扰柠,這里的host是服務(wù)器的IP粉铐,就是你作為服務(wù)器的那臺(tái)設(shè)備的IP地址(可以在設(shè)置連接WiFi的那里看到),端口號(hào)8888就是服務(wù)器監(jiān)聽的端口號(hào)卤档,注意這里返回的bool值isConnect只是說是否能調(diào)用此方法蝙泼,具體是否連接上服務(wù)器要看是否調(diào)用代理-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port連接成功后就可以使用[self.tcpScoket writeData:data withTimeout:-1 tag:0];方法向服務(wù)器發(fā)數(shù)據(jù)了,收發(fā)消息的方法與上面服務(wù)器的相同劝枣,所觸發(fā)的代理一是一樣的汤踏。
這里自己寫了小程序socket tcp通信程序 鏈接: https://pan.baidu.com/s/1bI1gy6 密碼: 8tjv demo里有一個(gè)server,一個(gè)client.