關於iOS socket(套接字)

socket(套接字)是通訊的基石,是支持TCP/IP協議的網絡通訊的基本操做單元,包含進行網絡通訊必須的五種信息:鏈接使用的協議,本地主機的IP地址,本地進程的協議端口,遠地主機的IP地址,遠地進程的協議端口。git

多個TCP鏈接或多個應用程序進程可能須要經過同一個TCP協議端口傳輸數據。爲了區別不一樣的應用程序進程和鏈接,計算機操做系統爲應用程序與TCP/IP協議交互提供了套接字(Socket)接口。應用層能夠和傳輸層經過Socket接口,區分來自不一樣應用程序進程或網絡鏈接的通訊,實現數據傳輸的併發服務。github

創建Socket鏈接至少須要一對套接字,其中一個運行於客戶端,稱爲ClientSocket,另外一個運行於服務器端,稱爲ServerSocket。套接字之間的鏈接過程分爲三個步驟:服務器監聽,客戶端請求,鏈接確認。編程

Socket能夠支持不一樣的傳輸層協議(TCP或UDP),當使用TCP協議進行鏈接時,該Socket鏈接就是一個TCP鏈接,UDP鏈接同理。瀏覽器

1464766627371148.jpg

Socket使用安全

socket使用的庫函數服務器

1.建立套接字網絡

1併發

2socket

3async

Socket(af,type,protocol)//創建地址和套接字的聯繫

bind(sockid, local addr, addrlen)//服務器端偵聽客戶端的請求

listen( Sockid ,quenlen)//創建服務器/客戶端的鏈接 (面向鏈接TCP)

2.客戶端請求鏈接

1

2

Connect(sockid, destaddr, addrlen)//服務器端等待從編號爲Sockid的Socket上接收客戶鏈接請求

newsockid=accept(Sockid,Clientaddr, paddrlen)//發送/接收數據

3.面向鏈接:

1

2

send(sockid, buff, bufflen)

recv()

4.面向無鏈接:

1

2

sendto(sockid,buff,…,addrlen)

recvfrom()

5.釋放套接字

1

close(socked)

在iOS中以NSStream(流)來發送和接收數據,能夠設置流的代理,對流狀態的變化作出相應的動做(鏈接創建,接收到數據,鏈接關閉)。

  • NSStream:數據流的父類,用於定義抽象特性,例如:打開、關閉代理,NSStream繼承自CFStream(CoreFoundation)

  • NSInputStream:NSStream的子類,用於讀取輸入

  • NSOutputStream:NSSTream的子類,用於寫輸出。

服務端先不提,客戶端代碼大概以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

//須要導入<arpa inet.h="">,<netdb.h>

- (void)test

{

    NSString * host =@"123.33.33.1";

    NSNumber * port = @1233 ;

    // 建立 socket

    int socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0);

    if (-1 == socketFileDescriptor) {

        NSLog(@"建立失敗");

        return;

    }

    // 獲取 IP 地址

    struct hostent * remoteHostEnt = gethostbyname([host UTF8String]);

    if (NULL == remoteHostEnt) {

        close(socketFileDescriptor);

        NSLog(@"%@",@"沒法解析服務器的主機名");

        return;

    }

    struct in_addr * remoteInAddr = (struct in_addr *)remoteHostEnt->h_addr_list[0];

    // 設置 socket 參數

    struct sockaddr_in socketParameters;

    socketParameters.sin_family = AF_INET;

    socketParameters.sin_addr = *remoteInAddr;

    socketParameters.sin_port = htons([port intValue]);

    // 鏈接 socket

    int ret = connect(socketFileDescriptor, (struct sockaddr *) &socketParameters, sizeof(socketParameters));

    if (-1 == ret) {

        close(socketFileDescriptor);

        NSLog(@"鏈接失敗");

        return;

    }

    NSLog(@"鏈接成功");

}</netdb.h></arpa>

大概就是這樣,由於是C語言的,因此看起來不是很方便,通常開發中都會使用比較簡單的方法,以下。

CocoaAsyncSocket

iOS的socket實現是特別簡單的,可使用用github的開源類庫cocoaasyncsocket簡化開發,cocoaasyncsocket是支持tcp和ump的。代碼大概以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

- (IBAction)connectToServer:(id)sender {

    // 1.與服務器經過三次握手創建鏈接

    NSString *host = @"133.33.33.1";

    int port = 1212;

    //建立一個socket對象

    _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];

    //鏈接

    NSError *error = nil;

    [_socket connectToHost:host onPort:port error:&error];

        if (error) {

            NSLog(@"%@",error);

        }

    }

    #pragma mark -socket的代理

    #pragma mark 鏈接成功

    -(void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port{

        NSLog(@"%s",__func__);

    }

    #pragma mark 斷開鏈接

    -(void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err{

    if (err) {

        NSLog(@"鏈接失敗");

    }else{

        NSLog(@"正常斷開");

    }

}

#pragma mark 數據發送成功

-(void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag{

NSLog(@"%s",__func__);

//發送完數據手動讀取,-1不設置超時

[sock readDataWithTimeout:-1 tag:tag];

}

#pragma mark 讀取數據

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag{

NSString *receiverStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

NSLog(@"%s %@",__func__,receiverStr);

}

下面是原理補充,有興趣的朋友能夠細看。

網絡七層協議

網絡七層協議由下往上分別爲物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。其中物理層、數據鏈路層和網絡層一般被稱做媒體層,是網絡工程師所研究的對象;傳輸層、會話層、表示層和應用層則被稱做主機層,是用戶所面向和關心的內容。

HTTP協議對應於應用層,TCP協議對應於傳輸層,IP協議對應於網絡層,HTTP協議是基於TCP鏈接的,三者本質上沒有可比性。 TCP/IP是傳輸層協議,主要解決數據如何在網絡中傳輸;而HTTP是應用層協議,主要解決如何包裝數據。Socket是應用層與TCP/IP協議族通訊的中間軟件抽象層,是它的一組接口。

1170656-1ceffddc43357839.jpg

網絡七層協議

TCP/IP五層模型

TCP/IP五層模型的協議分爲:應用層、傳輸層、網絡層、數據鏈路層和物理層。中繼器、集線器、還有咱們一般說的雙絞線也工做在物理層;網橋(現已不多使用)、以太網交換機(二層交換機)、網卡(其實網卡是一半工做在物理層、一半工做在數據鏈路層)在數據鏈路層;路由器、三層交換機在網絡層;傳輸層主要是四層交換機、也有工做在四層的路由器。

TCP/IP協議中的應用層處理七層模型中的第五層、第六層和第七層的功能。TCP/IP協議中的傳輸層並不能老是保證在傳輸層可靠地傳輸數據包,而七層模型能夠作到。TCP/IP協議還提供一項名爲UDP(用戶數據報協議)的選擇。UDP不能保證可靠的數據包傳輸。

1170656-df46648a7fadfa42.jpg

對應關係

  • TCP:面向鏈接、傳輸可靠(保證數據正確性,保證數據順序)、用於傳輸大量數據(流模式)、速度慢,創建鏈接須要開銷較多(時間,系統資源)。

  • UDP:面向非鏈接、傳輸不可靠、用於傳輸少許數據(數據包模式)、速度快。

TCP是一種流模式的協議,UDP是一種數據報模式的協議。

在傳輸數據時,能夠只使用傳輸層(TCP/IP),可是那樣的話,因爲沒有應用層,便沒法識別數據內容,若是想要使傳輸的數據有意義,則必須使用應用層協議(HTTP、FTP、TELNET等),也能夠本身定義應用層協議。

WEB使用HTTP做傳輸層協議,以封裝HTTP文本信息,而後使用TCP/IP作傳輸層協議將它發送到網絡上。Socket是對TCP/IP協議的封裝,Socket自己並非協議,而是一個調用接口(API),經過Socket,咱們才能使用TCP/IP協議。

1170656-fe177ff611c71d76.jpg

Socket的位置

TCP鏈接

要想明白Socket鏈接,先要明白TCP鏈接。手機可以使用聯網功能是由於手機底層實現了TCP/IP協議,可使手機終端經過無線網絡創建TCP鏈接。TCP協議能夠對上層網絡提供接口,使上層網絡數據的傳輸創建在「無差異」的網絡之上。

創建起一個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狀態,完成三次握手。

三次握手(Three-way Handshake)即創建一個TCP鏈接時,須要客戶端和服務器總共發送3個包。三次握手的目的是鏈接服務器指定端口,創建TCP鏈接,並同步鏈接雙方的序列號和確認號並交換TCP 窗口大小信息。在socket編程中,客戶端執行connect()時,將觸發三次握手。

1170656-a3120a20b9393a94.png

三次握手

握手過程當中傳送的包裏不包含數據,三次握手完畢後,客戶端與服務器才正式開始傳送數據。理想狀態下,TCP鏈接一旦創建,在通訊雙方中的任何一方主動關閉鏈接以前,TCP 鏈接都將被一直保持下去。斷開鏈接時服務器和客戶端都可以主動發起斷開TCP鏈接的請求,斷開過程須要通過「四次握手」。

TCP鏈接的拆除須要發送四個包,所以稱爲四次握手(four-way handshake)。在socket編程中,任何一方執行close()操做便可產生握手(有地方稱爲「揮手」)操做。

1464767137254402.jpg

TCP鏈接的拆除

之因此有「三次握手」和「四次握手」的區別,是由於鏈接時當Server端收到Client端的SYN鏈接請求報文後,能夠直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。可是關閉鏈接時,當Server端收到FIN報文時,極可能並不會當即關閉SOCKET,因此只能先回復一個ACK報文,告訴Client端,」你發的FIN報文我收到了」。只有等到我Server端全部的報文都發送完了,我才能發送FIN報文,所以不能一塊兒發送。故須要四步握手。

HTTP鏈接

HTTP協議即超文本傳送協議(HypertextTransfer Protocol ),是Web聯網的基礎,也是手機聯網經常使用的協議之一,HTTP協議是創建在TCP協議之上的一種應用。

HTTP鏈接最顯著的特色是客戶端發送的每次請求都須要服務器回送響應,在請求結束後,會主動釋放鏈接。從創建鏈接到關閉鏈接的過程稱爲「一次鏈接」。所以HTTP鏈接是一種「短鏈接」,要保持客戶端程序的在線狀態,須要不斷地向服務器發起鏈接請求。若服務器長時間沒法收到客戶端的請求,則認爲客戶端「下線」,若客戶端長時間沒法收到服務器的回覆,則認爲網絡已經斷開。在HTTP 1.0中,客戶端的每次請求都要求創建一次單獨的鏈接,在處理完本次請求後,就自動釋放鏈接。在HTTP 1.1中則能夠在一次鏈接中處理多個請求,而且多個請求能夠重疊進行,不須要等待一個請求結束後再發送下一個請求。

HTTPS(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全爲目標的HTTP通道,是HTTP的安全版。 在HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL。 HTTPS存在不一樣於HTTP的默認端口及一個加密/身份驗證層(在HTTP與TCP之間)。HTTP協議以明文方式發送內容,不提供任何方式的數據加密,若是攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文,就能夠直接讀懂其中的信息,所以HTTP協議不適合傳輸一些敏感信息。

https協議須要到ca申請證書;http是超文本傳輸協議,信息是明文傳輸,https 則是具備安全性的ssl加密傳輸協議;http和https使用的是徹底不一樣的鏈接方式,用的端口也不同,前者是80,後者是443;http的鏈接很簡單,是無狀態的,HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議。

1170656-0601aab8deb7df8d.jpeg

HTTPS

Socket鏈接與HTTP鏈接的不一樣

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

而HTTP鏈接使用的是「請求—響應」的方式,不只在請求時須要先創建鏈接,並且須要客戶端向服務器發出請求後,服務器端才能回覆數據。

相關文章
相關標籤/搜索