Socket的基本概念
1.定義
網(wǎng)絡(luò)上兩個(gè)程序通過(guò)一個(gè)雙向通信連接實(shí)現(xiàn)數(shù)據(jù)交互,這種雙向通信的連接叫做Socket(套接字)碳蛋。
2.本質(zhì)
網(wǎng)絡(luò)模型中應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層,是它的一組編程接口(API)省咨,也即對(duì)TCP/IP的封裝肃弟。TCP/IP也要提供可供程序員做網(wǎng)絡(luò)開(kāi)發(fā)所用的接口,即Socket編程接口零蓉。
Socket的位置
3.要素
Socket是網(wǎng)絡(luò)通信的基石笤受,是支持TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本操作單元,包含進(jìn)行網(wǎng)絡(luò)通信的必須的五種信息:
連接使用的協(xié)議
本地主機(jī)的IP地址
本地進(jìn)程的協(xié)議端口
遠(yuǎn)程主機(jī)的IP地址
遠(yuǎn)程進(jìn)程的協(xié)議端口
4.特性
Socket可以支持不同的傳輸協(xié)議(TCP或UDP)壁公,當(dāng)使用TCP協(xié)議進(jìn)行連接時(shí)感论,該Socket連接就是一個(gè)TCP連接;同理紊册,當(dāng)使用UDP協(xié)議進(jìn)行連接時(shí)比肄,該Socket連接就是一個(gè)UDP連接。
多個(gè)TCP連接或多個(gè)應(yīng)用程序進(jìn)程可能需要通過(guò)同一個(gè)TCP協(xié)議端口傳輸數(shù)據(jù)囊陡。為了區(qū)別不同的應(yīng)用程序進(jìn)程和連接芳绩,計(jì)算機(jī)操作系統(tǒng)為應(yīng)用程序與TCP/IP協(xié)議交互提供了套接字(Socket)接口。應(yīng)用層可以和傳輸層通過(guò)Socket接口撞反,區(qū)分來(lái)自不同應(yīng)用程序進(jìn)程或網(wǎng)絡(luò)連接的通信妥色,實(shí)現(xiàn)數(shù)據(jù)傳輸?shù)牟l(fā)服務(wù)。
5.連接
建立Socket連接至少需要一對(duì)套接字遏片,分別運(yùn)行于服務(wù)端(ServerSocket)和客戶端(ClientSocket)嘹害。套接字直接的連接過(guò)程氛圍三個(gè)步驟:
Step1服務(wù)器監(jiān)聽(tīng)
服務(wù)端Socket始終處于等待連接狀態(tài)撮竿,實(shí)時(shí)監(jiān)聽(tīng)是否有客戶端請(qǐng)求連接。
Step2客戶端請(qǐng)求
客戶端Socket提出連接請(qǐng)求笔呀,指定服務(wù)端Socket的地址和端口號(hào)幢踏,這時(shí)就可以向?qū)?yīng)的服務(wù)端提出Socket連接請(qǐng)求。
Step3連接確認(rèn)
當(dāng)服務(wù)端Socket監(jiān)聽(tīng)到客戶端Socket提出的連接請(qǐng)求時(shí)作出響應(yīng)许师,建立一個(gè)新的進(jìn)程房蝉,把服務(wù)端Socket的描述發(fā)送給客戶端,該描述得到客戶端確認(rèn)后就可建立起Socket連接微渠。而服務(wù)端Socket則繼續(xù)處于監(jiān)聽(tīng)狀態(tài)搭幻,繼續(xù)接收其他客戶端Socket的請(qǐng)求。
iOS客戶端Socket的實(shí)現(xiàn)
1. 數(shù)據(jù)流方式
? ? - (IBAction)connectToServer:(id)sender {
? ? ? ? // 1.與服務(wù)器通過(guò)三次握手建立連接
? ? ? ? NSString *host = @"192.168.1.58";
? ? ? ? int port =1212;
? ? ? ? //創(chuàng)建一個(gè)socket對(duì)象
? ? ? ? _socket = [[GCDAsyncSocket alloc] initWithDelegate:self
? ? ? ? ? ? delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)];
? ? ? ? NSError *error =nil;
? ? ? ? // 開(kāi)始連接
? ? ? ? [_socket connectToHost:host
? ? ? ? ? ? onPort:port
? ? ? ? ? ? error:&error];
? ? ? ? if(error) {
? ? ? ? ? ? NSLog(@"%@",error);
? ? ? ? }
}
#pragma mark - Socket代理方法
// 連接成功
- (void)socket:(GCDAsyncSocket *)sock
didConnectToHost:(NSString *)host
port:(uint16_t)port {
? ? NSLog(@"%s",__func__);
? ? }
? ? // 斷開(kāi)連接
? ? - (void)socketDidDisconnect:(GCDAsyncSocket *)sock
withError:(NSError *)err {
? ? if(err) {
? ? ? ? NSLog(@"連接失敗");
? ? }else{
? ? ? ? NSLog(@"正常斷開(kāi)");
? ? }
? ? }
? ? // 發(fā)送數(shù)據(jù)
? ? - (void)socket:(GCDAsyncSocket *)sock
didWriteDataWithTag:(long)tag {
? ? NSLog(@"%s",__func__);
? ? //發(fā)送完數(shù)據(jù)手動(dòng)讀取逞盆,-1不設(shè)置超時(shí)
? ? [sock readDataWithTimeout:-1
? ? ? ? tag:tag];
}
// 讀取數(shù)據(jù)
-(void)socket:(GCDAsyncSocket *)sock
didReadData:(NSData *)data
withTag:(long)tag {
? ? NSString *receiverStr = [[NSString alloc] initWithData:data
? ? ? ? encoding:NSUTF8StringEncoding];
? ? NSLog(@"%s %@",__func__,receiverStr);
}
2.基于第三方開(kāi)源庫(kù)CocoaAsyncSocket
2.1客戶端通過(guò)地址和端口號(hào)與服務(wù)端建立Socket連接檀蹋,并寫入相關(guān)數(shù)據(jù)。
? ? - (void)connectToServerWithCommand:(NSString *)command
{
? ? _socket = [[GCDAsyncSocket alloc] initWithDelegate:selfdelegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)];
? ? [_socket setUserData:command];
? ? NSError *error =nil;
? ? [_socket connectToHost:WIFI_DIRECT_HOST onPort:WIFI_DIRECT_PORT error:&error];
? ? if(error) {
? ? ? ? NSLog(@"__connect error:%@",error.userInfo);
? ? }
? ? [_socket writeData:[command dataUsingEncoding:NSUTF8StringEncoding] withTimeout:10.0f tag:6];
}
2.2實(shí)現(xiàn)CocoaAsyncSocket的代理方法
#pragma mark - Socket Delegate
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
? ? NSLog(@"Socket連接成功:%s",__func__);
}
-(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{
? ? if(err) {
? ? ? ? NSLog(@"連接失敗");
? ? }else{
? ? ? ? NSLog(@"正常斷開(kāi)");
? ? }
? ? if([sock.userData isEqualToString:[NSString stringWithFormat:@"%d",SOCKET_CONNECT_SERVER]])
? ? {
? ? ? ? //服務(wù)器掉線 重新連接
? ? ? ? [selfconnectToServerWithCommand:@"battery"];
? ? }else
? ? {
? ? ? ? return;
? ? }
}
-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
? ? NSLog(@"數(shù)據(jù)發(fā)送成功:%s",__func__);
? ? //發(fā)送完數(shù)據(jù)手動(dòng)讀取纳击,-1不設(shè)置超時(shí)
? ? [sock readDataWithTimeout:-1tag:tag];
}
-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
? ? NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
? ? NSLog(@"讀取數(shù)據(jù):%s %@",__func__,receiverStr);
}