1.網絡的各個協議git
2.Socket原理github
網絡七層由下往上分別爲物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。網絡
OSI七層網絡模型
|
TCP/IP四層概念模型
|
對應網絡協議
|
應用層(Application)
|
應用層
|
TFTP, FTP, NFS, WAIS
|
表示層(Presentation)
|
Telnet, Rlogin, SNMP, Gopher
|
|
會話層(Session)
|
SMTP, DNS
|
|
傳輸層(Transport)
|
傳輸層
|
TCP, UDP
|
網絡層(Network)
|
網際層
|
IP, ICMP, ARP, RARP, AKP, UUCP
|
數據鏈路層(Data Link)
|
網絡接口
|
FDDI, Ethernet, Arpanet, PDN, SLIP, PPP
|
物理層(Physical)
|
IEEE 802.1A, IEEE 802.2到IEEE 802.11
|
網絡七層協議併發
應用層:
1.用戶接口、應用程序;socket
2.Application典型設備:網關;tcp
3.典型協議、標準和應用:TELNET、FTP、HTTPide
表示層:
1.數據表示、壓縮和加密presentation工具
2.典型設備:網關
3.典型協議、標準和應用:ASCLL、PICT、TIFF、JPEG|MPEG
4.表示層至關於一個東西的表示,表示的一些協議,好比圖片、聲音和視頻MPEG。
會話層:
1.會話的創建和結束;
2.典型設備:網關;
3.典型協議、標準和應用:RPC、SQL、NFS、X WINDOWS、ASP
傳輸層:
1.主要功能:端到端控制Transport;
2.典型設備:網關;
3.典型協議、標準和應用:TCP、UDP、SPX
網絡層:
1.主要功能:路由、尋址Network;
2.典型設備:路由器;
3.典型協議、標準和應用:IP、IPX、APPLETALK、ICMP;
數據鏈路層:
1.主要功能:保證無差錯的疏忽鏈路的data link;
2.典型設備:交換機、網橋、網卡;
3.典型協議、標準和應用:802.二、802.3ATM、HDLC、FRAME RELAY;
物理層:
1.主要功能:傳輸比特流Physical;
2.典型設備:集線器、中繼器
3.典型協議、標準和應用:V.3五、EIA/TIA-232.
http協議 對應於應用層
tcp協議 對應於傳輸層
ip協議 對應於網絡層
三者本質上沒有可比性。 況且HTTP協議是基於TCP鏈接的。
TCP(Transmission Control Protocol,傳輸控制協議)是面向鏈接的協議,也就是說,在收發數據前,必須和對方創建可靠的鏈接。
UDP(User Data Protocol,用戶數據報協議)
(1) UDP是一個非鏈接的協議,傳輸數據以前源端和終端不創建鏈接,當它想傳送時就簡單地去抓取來自應用程序的數據,並儘量快地把它扔到網絡上。在發送端,UDP傳送數據的速度僅僅是受應用程序生成數據的速度、計算機的能力和傳輸帶寬的限制;在接收端,UDP把每一個消息段放在隊列中,應用程序每次從隊列中讀一個消息段。
(2) 因爲傳輸數據不創建鏈接,所以也就不須要維護鏈接狀態,包括收發狀態等,所以一臺服務機可同時向多個客戶機傳輸相同的消息。
(3) UDP信息包的標題很短,只有8個字節,相對於TCP的20個字節信息包的額外開銷很小。
(4) 吞吐量不受擁擠控制算法的調節,只受應用軟件生成數據的速率、傳輸帶寬、源端和終端主機性能的限制。
(5)UDP使用盡最大努力交付,即不保證可靠交付,所以主機不須要維持複雜的連接狀態表(這裏面有許多參數)。
(6)UDP是面向報文的。發送方的UDP對應用程序交下來的報文,在添加首部後就向下交付給IP層。既不拆分,也不合並,而是保留這些報文的邊界,所以,應用程序須要選擇合適的報文大小。
咱們在傳輸數據時,能夠只使用傳輸層(TCP/IP),可是那樣的話,因爲沒有應用層,便沒法識別數據內容,若是想要使傳輸的數據有意義,則必須使用應用層 協議,應用層協議不少,有HTTP、FTP、TELNET等等,也能夠本身定義應用層協議。WEB使用HTTP做傳輸層協議,以封裝HTTP文本信息,然 後使用TCP/IP作傳輸層協議將它發送到網絡上。Socket是對TCP/IP協議的封裝,Socket自己並非協議,而是一個調用接口(API),經過Socket,咱們才能使用TCP/IP協議。
3.1.套接字(Socket)概念
套接字(Socket)是通訊的基石,是支持TCP/IP協議的網絡通訊的基本操做單元。它是網絡通訊過程當中端點的抽象表示,包含進行網絡通訊必須的五種信息:鏈接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。
應用層經過傳輸層進行數據通訊時,TCP會遇到同時爲多個應用程序進程提供併發服務的問題。多個TCP鏈接或多個應用程序進程可能須要經過同一個 TCP協議端口傳輸數據。爲了區別不一樣的應用程序進程和鏈接,許多計算機操做系統爲應用程序與TCP/IP協議交互提供了套接字(Socket)接口。應 用層能夠和傳輸層經過Socket接口,區分來自不一樣應用程序進程或網絡鏈接的通訊,實現數據傳輸的併發服務。
3.2.創建Socket鏈接
創建Socket鏈接至少須要一對套接字,其中一個運行於客戶端,稱爲ClientSocket,另外一個運行於服務器端,稱爲ServerSocket。
套接字之間的鏈接過程分爲三個步驟:服務器監聽,客戶端請求,鏈接確認。
服務器監聽:服務器端套接字並不定位具體的客戶端套接字,而是處於等待鏈接的狀態,實時監控網絡狀態,等待客戶端的鏈接請求。
客戶端請求:指客戶端的套接字提出鏈接請求,要鏈接的目標是服務器端的套接字。爲此,客戶端的套接字必須首先描述它要鏈接的服務器的套接字,指出服務器端套接字的地址和端口號,而後就向服務器端套接字提出鏈接請求。
鏈接確認:當服務器端套接字監聽到或者說接收到客戶端套接字的鏈接請求時,就響應客戶端套接字的請求,創建一個新的線程,把服務器端套接字的描述發給客戶 端,一旦客戶端確認了此描述,雙方就正式創建鏈接。而服務器端套接字繼續處於監聽狀態,繼續接收其餘客戶端套接字的鏈接請求。
3.3.Socket鏈接,TCP鏈接
建立Socket鏈接時,能夠指定使用的傳輸層協議,Socket能夠支持不一樣的傳輸層協議(TCP或UDP),當使用TCP協議進行鏈接時,該Socket鏈接就是一個TCP鏈接。
3.4.Socket鏈接,Http鏈接
因爲一般狀況下Socket鏈接就是TCP鏈接,所以Socket鏈接一旦創建,通訊雙方便可開始相互發送數據內容,直到雙方鏈接斷開。但在實際網絡應用 中,客戶端到服務器之間的通訊每每須要穿越多箇中間節點,例如路由器、網關、防火牆等,大部分防火牆默認會關閉長時間處於非活躍狀態的鏈接而致使 Socket鏈接斷連,所以須要經過輪詢告訴網絡,該鏈接處於活躍狀態。
而Http鏈接使用的是「請求—響應」的方式,不只在請求時須要先創建鏈接,並且須要客戶端向服務器發出請求後,服務器端才能回覆數據。不少狀況下,須要服務器端主動向客戶端推送數據,保持客戶端與服務器數據的實時與同步。此時若雙方創建的是Socket鏈接,服務器就能夠直接將數據傳送給客戶端;若雙方創建的是HTTP鏈接,則服務器須要等到客戶端發送一次請求後才能將數據傳回給客戶端,所以,客戶端定時向服務器端發送鏈接請求,不只能夠保持在線,同時也是在「詢問」服務器是否有新的數據,若是有就將數據傳給客戶端。
下載地址:https://github.com/robbiehanson/CocoaAsyncSocket
裏面有GCDAsyncSocket(TCP)和GCDAsyncUdpSocket(UDP)
例:服務端在Windows電腦上找個第三方工具
//ViewController.m文件
// // ViewController.m // SockerLearn // // Created by Vie on 2017/2/9. // Copyright © 2017年 Vie. All rights reserved. // #import "ViewController.h" #import "GCDAsyncSocket.h" @interface ViewController ()<GCDAsyncSocketDelegate> @property(nonatomic,strong) GCDAsyncSocket *socket; @end @implementation ViewController -(GCDAsyncSocket *)socket{ if (!_socket) { //建立一個socket對象,代理方法都會在子線程調用,在刷新UI時就要回到主線程 _socket=[[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)]; _socket.IPv4PreferredOverIPv6 = NO; // 設置支持IPV6 } return _socket; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. float heightBtn=50; float widthBtn=self.view.frame.size.width*0.8; float btnX=(self.view.frame.size.width-widthBtn)/2; //鏈接服務器按鈕 UIButton *connectBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 100, widthBtn, heightBtn)]; [connectBtn setTitle:@"鏈接服務器" forState:UIControlStateNormal]; [connectBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [connectBtn.layer setCornerRadius:8.0f]; [connectBtn addTarget:self action:@selector(connectAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:connectBtn]; //登錄按鈕(登錄其實就是發送消息校驗) UIButton *loginBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 180, widthBtn, heightBtn)]; [loginBtn setTitle:@"登錄驗證" forState:UIControlStateNormal]; [loginBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [loginBtn.layer setCornerRadius:8.0f]; [loginBtn addTarget:self action:@selector(loginAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:loginBtn]; //斷開鏈接 UIButton *closeBtn=[[UIButton alloc] initWithFrame:CGRectMake(btnX, 260, widthBtn, heightBtn)]; [closeBtn setTitle:@"斷開鏈接" forState:UIControlStateNormal]; [closeBtn setBackgroundColor:[UIColor colorWithRed:104/255.0 green:200/255.0 blue:250/255.0 alpha:1]]; [closeBtn.layer setCornerRadius:8.0f]; [closeBtn addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:closeBtn]; } //鏈接Socket服務 -(void)connectAction:(UIButton *)sender{ NSLog(@"鏈接Socket服務器"); NSString *host=@"192.168.191.1"; int port=5678; //鏈接服務器 NSError *error=nil; // [self.socket connectToHost:host onPort:port error:&error]; //設置鏈接超時時間 [self.socket connectToHost:host onPort:port withTimeout:15 error:&error]; if (error) { NSLog(@"%@",error); } } //發送消息Socket登錄驗證 -(void)loginAction:(UIButton *)sender{ NSLog(@"發送消息Socket登錄驗證"); //登錄指令(本質是發送消息接收消息) NSString *loginInfo=@"Vie:123456\n"; NSData *data=[loginInfo dataUsingEncoding:NSUTF8StringEncoding]; //-1不設置超時 [self.socket writeData:data withTimeout:-1 tag:0]; } //斷開Socket鏈接 -(void)closeAction:(UIButton *)sender{ NSLog(@"斷開Socket鏈接"); [self.socket disconnect]; } #pragma mark GCDAsyncSocketDelegate數據發送成功執行回調 -(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{ NSLog(@"數據成功發送到服務器"); //本身調用下讀取數據的方法,接着Socket纔會執行didReadData(每當你接收到數據以後,須要再次設置) [self.socket readDataWithTimeout:-1 tag:tag]; } #pragma mark GCDAsyncSocketDelegate接收到數據 -(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{ //將接收到的數據轉換成字符串,中文編碼要一致 NSString *responseString=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"收到數據tag:%ld 內容:%@",tag,responseString); //每次讀完數據後,都要調用一次監聽數據的方法Socket纔會執行didReadData [self.socket readDataWithTimeout:-1 tag:tag]; } #pragma mark GCDAsyncSocketDelegate鏈接服務器結果回調 -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{ NSLog(@"鏈接主機成功"); } -(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{ if (err) { NSLog(@"鏈接失敗"); }else{ NSLog(@"正常斷開"); } } @end