1、HTTP協議的主要特色:css
1. CS模式
2. 簡單快速:只須要傳送請求方法和路徑。(經常使用方法有GET,HEAD,POST)
3. 靈活:任意對象均可以,類型由Content-Type加以標記
4. 無鏈接、無狀態 即每次鏈接只處理一個請求,對於事務處理沒有記憶能力
http表示要經過HTTP協議來定位網絡資源;host表示合法的Internet主機域名或者IP地址;port制定一個端口號,爲空時使用缺省端口號80;abs_path指定請求資源的URI;若是URL中沒有給出abs_path,那麼當它做爲請求URI時,必須以「/」的形式給出(此過程由瀏覽器完成)。ios
2、TCP/UDP區別和聯繫
1.TCP是面向鏈接的可靠的傳輸控制協議,UDP是面向非鏈接的用戶數據報協議.
2.TCP(三次握手保證相對可靠性)可傳大量數據,速度相對比較慢,UDP一次性傳輸少許對可靠性要求不高的數據,速度比較快
tcp通常用於音頻、視頻等數據的傳輸,資源能耗比較小,對可靠性要求不高,即便丟失一兩條數據也不會產生太大影響。git
3、Socket鏈接和Http鏈接的區別
1.http是基於socket之上的,socket是一套完成tcp和udp協議的接口
2.HTTP協議:簡單對象訪問協議,對應於應用層 ,HTTP協議是基於TCP鏈接的
3.tcp協議: 對應於傳輸層
4.ip協議: 對應於網絡層
TCP/IP是傳輸層協議,主要解決數據如何在網絡中傳輸;而HTTP是應用層協議,主要解決如何包裝數據。
Socket是對TCP/IP協議的封裝,Socket自己並非協議,而是一個調用接口(API),經過Socket,咱們才能使用TCP/IP協議。
http是短鏈接,客戶端向服務端發送一次請求,服務端響應後鏈接即斷掉;socket是長鏈接,通常狀況下,若是服務器端或者客戶端主機down了,網絡故障,或者二者長時間沒有數據傳輸,鏈接可能會斷。因此當以個socket鏈接中沒有數據的傳輸,爲了維持鏈接須要發送心跳消息。github
4、三次握手的過程再也不贅述,主要來了解下socket創建網絡鏈接的步驟
創建socket鏈接至少須要一堆套接字,其中一個運行於客戶端,另外一個運行於服務端(ClientSocket、ServerSocket)
套接字創建鏈接的過程分爲三步:服務器監聽、客戶端請求、鏈接確認
1。服務器監聽:服務器端套接字並不定位具體的客戶端套接字,而是處於等待鏈接的狀態,實時監控網絡狀態,等待客戶端的鏈接請求。
2。客戶端請求:指客戶端的套接字提出鏈接請求,要鏈接的目標是服務器端的套接字。爲此,客戶端的套接字必須首先描述它要鏈接的服務器的套接字,指出服務器端套接字的地址和端口號,而後就向服務器端套接字提出鏈接請求。
3。鏈接確認:當服務器端套接字監聽到或者說接收到客戶端套接字的鏈接請求時,就響應客戶端套接字的請求,創建一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,雙方就正式創建鏈接。而服務器端套接字繼續處於監聽狀態,繼續接收其餘客戶端套接字的鏈接請求。編程
5、HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。數組
AsyncSocket是IOS下專門用於socket套接字開發的開源庫,它封裝了CFNetwork/BSD Socket.提供了異步的開發模型和簡便的開發接口。它支持TCP/UDP,支持UDP組播
AsyncSocket支持GCD/Runloop模式 支持ARC 使用時須要增長兩個庫 CFNetwork.frame和Security.framexcode
6、UDP編程
server端流程:
1. socket建立套接字
2. bind綁定port
3. recv接收、send發送數據
4. close關閉socket套接字
client端流程
1.socket建立套接字
2.bind綁定port端口(可選)
3. recv接收 send發送數據
4. close關閉socket套機制瀏覽器
UDP編程涉及到 ip和字符串的轉化以下
/*綁定ip地址 */ inet_pton(AF_INET,"192.168.101.2",&addr.sin_addr); /*把地址sin_addr轉化成字符串ipBuf*/ inet_ntop(AF_INET,&srcaddr.sin_addr,ipBuf,16);
UDP基本API
1. 建立UDP的套接字int sd = socket(AF_INET,SOCK_DGRAM,0);
2. 設置端口能夠重用 int nOptval = 1;
ret = setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,(const void*)&nOptval,sizeof(int));
3. 綁定端口 ret = bind(sd,(struct sockaddr *)&addr,addrlen);
4. 給某個地址發送數據ssize_t sendLen = sendto(sd,res,strlen(res),0,(struct sockaddr *)&srcaddr,sizeof(srcaddr));
5. 接收來自sd的數據ssize_t recvLen = recvfrom(sd,&info,sizeof(info),0,(struct sockaddr *)&srcaddr,&addrlen);
6. 關閉套接字 Close(sd);
安全
UDP 編程示例
server端 : 新建工程 Cococa Application 引入AsyncSocket
引入頭文件 #import 「AsyncUdpSocket.h」 以及代理 AsyncUdpSocketDelegate服務器
_udpSocketServer = [[AsyncUdpSocket alloc] initWithDelegate:self]; //綁定端口 用於標識socket對象 if(![_udpSocketServer bindToPort:5678 error:nil]){ NSLog(@"綁定失敗"); } //監聽狀態 是否有客戶端發送來的消息 [_udpSocketServer receiveWithTimeout:-1 tag:100];
代理回調
#pragma maek- socketDelegate //收到消息時的回調 -(BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ NSLog(@"port:%d",port); NSString* messege = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"recieve:%@",messege); [sock receiveWithTimeout:-1 tag:200]; return YES; }
上述代碼便可實現簡單的UDPServer端
UDPClient 代碼(簡單示例)
一樣的要聲明UDP對象 而後發送消息
NSString* messege = @"UDPClient 消息"; NSData* data = [messege dataUsingEncoding:NSUTF8StringEncoding]; /* *發送消息 host: 制定服務器的ip地址 port: 服務器的端口 -1 不限時發送 tag 對這次操做的標記 */ [_clientSocket sendData:data toHost:@"127.0.0.1" port:5678 withTimeout:-1 tag:0]; /*發送成功的回調方法是*/ - (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{ NSLog(@"發送成功!"); }
TCP編程
server端流程
1. socket建立socket套接字
2. bind綁定port端口
3. listen監聽端口
4. close關閉socket套機制
client端流程
1.socket建立套接字
2.bind綁定port端口(可選)
3.connect服務器端口
4.close關閉socket套機制
瞭解下 tcp的重傳策略: TCP用於控制數據段是否須要重傳的依據是設立重發定時器。在發送一個數據段的同時啓動一個重發定時器,AC(Ackonowlegement)就關閉該定時器,若是在定時器超時前沒有收到確認,則重傳該數據段。在選擇重發時間的過程當中,TCP必須具備自適應性。它須要根據互聯網當時的通訊狀況,給出合適的數據重發。
TCP編程實例
server
1.引入頭文件 #import 「AsyncSocket.h」 AsyncSocketDelegate
_tcpServer = [[AsyncSocket alloc]initWithDelegate:self]; //服務端對應的ip地址和端口,_serverSocket負責監聽是否有客戶端接入 //[_tcpServer acceptOnInterface:@"127.0.0.1" port:5678 error:nil]; //服務端負責監聽是否有客戶端接入此端口,host能夠缺省不寫 [_tcpServer acceptOnPort:5678 error:nil];
2.發現有客戶端接入時響應
-(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket{ NSLog(@"new socket host:%@ port:%d",newSocket.connectedHost,newSocket.connectedPort); //將新生成的socket對象加入數組中 [_array addObject:newSocket]; //負責不限時的監聽客戶端是否發送消息過來 [newSocket readDataWithTimeout:-1 tag:1]; }
3 收到客戶端發送過來的消息時
-(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"receive:%@",message); //告訴sock,繼續監聽客戶端 [sock readDataWithTimeout:-1 tag:2]; }
4鏈接的客戶端長時間不活躍時觸發下面的方法
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err{ NSLog(@"willDisconnect!"); }
5 斷開鏈接時
//已經斷開鏈接 - (void)onSocketDidDisconnect:(AsyncSocket *)sock{ NSLog(@"%s",__FUNCTION__);//__FUNCTION__ 可以打印出當前函數的名稱,通常用於對程序進行暴力調試時 }
client編程
1. 初始化一個AsyncSocket對象
_clientSocket = [[AsyncSocket alloc] initWithDelegate:self];
2. 與指定的服務器進行鏈接
if (!_clientSocket) { //建立一個客戶端對象,並設置delegate _clientSocket = [[AsyncSocket alloc] initWithDelegate:self]; } //先判斷是否與指定服務器鏈接 if ([_clientSocket isConnected]) { //斷開鏈接 [_clientSocket disconnect]; } //與指定服務器鏈接 //connectToHost 服務端的ip地址 //port 服務端的端口:端口的值可隨意約定 [_clientSocket connectToHost:@"127.0.0.1" onPort:5678 error:nil];
3.發送消息
NSString *message = @"hello server!"; //將數據轉換成data NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; //將data發給服務器 //data 發送的數據, timeout:-1 不限時發送, tag,對這次交互的標記 [_clientSocket writeData:data withTimeout:-1 tag:0];
4.回調方法
//當客戶端與服務端鏈接成功時,調用此方法
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ NSLog(@"與服務器:%@ %d 相鏈接",host,port); } //消息發送成功後,調用此方法 - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"send!"); }
點解此處下載 demo
今天主要是tcp和udp的編程 明天更新 http和流媒體
iOS中的TCP,UDP,socket的學習
先貼一下以前學習過的代碼:
加入CFNetwork.framework,去github上下載AsyncSocket
TCP
- (void)viewDidLoad { [super viewDidLoad]; recvArray = [[NSMutableArray alloc] init]; //服務端 recvSocket = [[AsyncSocket alloc] initWithDelegate:self]; //客戶端 sendSocket = [[AsyncSocket alloc] initWithDelegate:self]; //服務端開始等待別的客戶端的連接 //65535 >5000 [recvSocket acceptOnPort:5678 error:nil]; //那麼何時接受到了連接 } //調用這個方法就證實接受到了一個連接 - (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket{ [recvArray addObject:newSocket]; //等待客戶端發送數據 [newSocket readDataWithTimeout:-1 tag:100]; //何時讀取到了數據 } //調用這個方法就證實接受到了客戶端發送的數據 - (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ NSString* str = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; contentView.text = [NSString stringWithFormat:@"%@\n對方說:%@",contentView.text,str]; //繼續等待服務端發送數據 [sock readDataWithTimeout:-1 tag:100]; } //============= //調用這個方法的時候,就證實連接成功 - (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port{ } - (void)sendText:(id)sender{ //若是沒連接,那麼去連接服務端 if (sendSocket.isConnected == NO) { [sendSocket connectToHost:ipField.text onPort:5678 withTimeout:60 error:nil]; //何時知道連接成功 } NSData* data = [sendField.text dataUsingEncoding:NSUTF8StringEncoding]; //發送數據 [sendSocket writeData:data withTimeout:60 tag:100]; //何時知道數據發送成功 } //調用這個方法,就證實數據發送成功 - (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag{ }
UDP
- (void)viewDidLoad { [super viewDidLoad]; recvSocket = [[AsyncUdpSocket alloc] initWithDelegate:self]; //綁定端口 [recvSocket bindToPort:5888 error:nil]; sendSocket = [[AsyncUdpSocket alloc] initWithDelegate:self]; [sendSocket bindToPort:5999 error:nil]; //等待接受數據 [recvSocket receiveWithTimeout:-1 tag:100]; //何時接受到了數據 } //調用這個方法的時候證實接收到了數據 - (BOOL)onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port{ NSString* str = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; contentView.text = [NSString stringWithFormat:@"%@\n%@:%@",contentView.text,host,str]; [recvSocket receiveWithTimeout:-1 tag:100]; return YES; } - (void)sendText:(id)sender{ NSData* data = [sendField.text dataUsingEncoding:NSUTF8StringEncoding]; //發送數據 [sendSocket sendData:data toHost:ipField.text port:5888 withTimeout:60 tag:100]; //何時發送成功 } //這裏就發送成功了 - (void)onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag{ }首先說一下他們直接的聯繫,UDP和TCP就像聲明的一個協議,是須要傳送的東西也就是內容,而scoket就像是一個通道,用於傳送這些內容,也就是用socket來實現。
UDP:UDP是一種面向無鏈接的用戶數據報服務(user data protocol),不須要和服務器也能交互,只須要知道ip和監聽端口,不須要連接沒有目的的socket,只是將數據報投遞出去,無論接收方是否成功接收到,所以是一種不可靠的傳輸,可能會形成數據丟包,但因爲這些特徵,傳輸效率要優於TCP。
TCP:TCP是一種面向鏈接的傳輸控制協議(transform contorl protocol),必需要和服務器交互,具備高安全性,可靠性,須要和服務器進行三次握手,能根據具體網絡擁堵狀況進行延時。
Socket:Socket有兩種鏈接操做方式,面向鏈接的和麪向無鏈接的。使用UDP就是面向無鏈接的,使用TCP就是面向鏈接的。使用UDP無須要指定一個socket目的地,而是用TCP必需要指定一個socket目的地,須要進行預連接,不然鏈接不到。
socket就像是API,二UDP/TCP就是協議,使用scoket來實現內容的傳送。
TCP的3次握手:
創建起一個TCP鏈接須要通過「三次握手」:
第一次握手:客戶端發送syn包(syn=j)到服務器,並進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時本身也發送一個SYN包(syn=k),即SYN+ACK包,此時服務器進入SYN_RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此包發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次握手。
握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。理想狀態下,TCP鏈接一旦創建,在通訊雙方中的任何一方主動關閉鏈接以前,TCP 鏈接都將被一直保持下去。斷開鏈接時服務器和客戶端都可以主動發起斷開TCP鏈接的請求,斷開過程須要通過「四次握手」(過程就不細寫了,就是服務器和客戶端交互,最終肯定斷開)