iOS,Socker編程

1.網絡的各個協議git

2.Socket原理github

3.CocoaAsyncSocket庫使用算法

網絡的各個協議服務器

網絡七層由下往上分別爲物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。網絡

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鏈接的。 

TCPTransmission Control Protocol,傳輸控制協議)是面向鏈接的協議,也就是說,在收發數據前,必須和對方創建可靠的鏈接。

 

UDPUser 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協議。

Socket原理

     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能夠支持不一樣的傳輸層協議(TCPUDP),當使用TCP協議進行鏈接時,該Socket鏈接就是一個TCP鏈接。

     3.4.Socket鏈接,Http鏈接

           因爲一般狀況下Socket鏈接就是TCP鏈接,所以Socket鏈接一旦創建,通訊雙方便可開始相互發送數據內容,直到雙方鏈接斷開。但在實際網絡應用 中,客戶端到服務器之間的通訊每每須要穿越多箇中間節點,例如路由器、網關、防火牆等,大部分防火牆默認會關閉長時間處於非活躍狀態的鏈接而致使 Socket鏈接斷連,所以須要經過輪詢告訴網絡,該鏈接處於活躍狀態。

           而Http鏈接使用的是「請求—響應」的方式,不只在請求時須要先創建鏈接,並且須要客戶端向服務器發出請求後,服務器端才能回覆數據。不少狀況下,須要服務器端主動向客戶端推送數據,保持客戶端與服務器數據的實時與同步。此時若雙方創建的是Socket鏈接,服務器就能夠直接將數據傳送給客戶端;若雙方創建的是HTTP鏈接,則服務器須要等到客戶端發送一次請求後才能將數據傳回給客戶端,所以,客戶端定時向服務器端發送鏈接請求,不只能夠保持在線,同時也是在「詢問」服務器是否有新的數據,若是有就將數據傳給客戶端。

CocoaAsyncSocket庫使用

        下載地址: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
相關文章
相關標籤/搜索