iOS網絡--socket(1)

一、預備知識

 1.計算機網絡的7層模型:

網絡的7層模型如上圖(左邊部分)所示,其中應用層,表示層,會話層現在統稱爲應用層,同時我們的開發就是建立在應用層之上的,而傳輸層及其以下的層都是比較底層的。

數據從應用層到達物理層轉換爲電信號的過程叫做封包,從物理層到應用層的過程叫做解包

在傳輸層有兩種協議:1.TCP協議    2.UDP協議

 1.1 TCP協議:TCP協議是面向連接的協議,意思就是說接收數據和傳輸數據的兩方在通信的過程中始終保持連接。TCP在建立連接的時候會有三次握手:                                                                    而在斷開連接的時候則有4次握手:

                                                         

通俗點理解就是 1.客戶端:"服務器在嗎?"                          通俗的理解就是:1.客戶端:"服務器我好了",       

                            2.服務器:"在呀"                                                                     2.服務器:"不需要數據了嗎?"                 

                            3.客戶端:"給我傳點數據吧"                                                  3.服務器:"不需要數據我要斷開連接了"

然後就建立了TCP連接。                                                                                  4.客戶端:"好的,可以斷開了"

PS:以上僅供理解,官方的概念解釋請移步百度百科。

由建立連接的三次握手和斷開連接的四次握手,可以看出TCP是正兒八經的面向連接的,必須建立連接的雙方都需要連接的或者都不需要連接的情況下才會建立或者斷開連接。

1.2 UDP協議,UDP協議是面向無連接的協議,就是說一方向另一方發送數據時,不會確認對方是否收到,只是專注於發送數據,有點類似於古時候的飛鴿傳書。而這種連接在網絡流媒體和遊戲中使用得較多。

二、socket

      1.什麼是socket

            socket的官方闡述爲套接字,相信大家都和我一樣,看到這三個字都是懵逼的。而socket的中文翻譯則是插座,socket是網絡7層模型中的應用層和傳輸層之間的橋樑。我們可以就把它理解爲插座,那麼插座有兩頭的也有三頭的,那socket是幾頭的呢?可以比較負責任地說 socket是兩頭的插座,這兩頭分別代表 IP地址和端口號。IP地址用來確定是哪一臺計算機,端口號確定這臺計算上提供的什麼服務,這樣就可以將這個插座插入到對應的插孔從而獲得相應的服務(數據)。

                                            

         

      2.使用socket進行客戶端和服務器端的通信

               由於scoket使用C語言來實現的(沒有談及第三方😯),所以具有跨平臺的特性,各個語言平臺上scoket的實現通信的方式大同小異,主要過程如下如下圖所示:

                2.1 服務端scoket

                  在OC中使用scoket需要導入一下下面的頭文件們:

#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <sys/types.h>

然後在viewDidAppear中操作

1、創建scoket:  socket()

viewDidAppear中

int serverScket = socket(PF_INET, SOCK_STREAM, 0);
if(serverScket == -1){
    NSLog(@"創建socket失敗");
}else{
    NSLog(@"創建socket成功");
}

創建scoket我們使用 socket(int domain,int type,int protocal); domain表示域,一般我們傳遞兩種:PF_INET , PF_INET6 前者表示IPv4,後者表示IPv6(PS:IPv6協議可以爲地球上的每一顆砂礫綁定一個IP地址);第二個參數表示連接的類型是TCP還是UDP。SOCK_STREAM表示TCP,SOCK_DGRAM表示UDP。第三個參數表示協議,我們傳0表示根據第二個參數來選擇協議。socket()函數的返回值爲一個狀態碼,表示socket是否創建成功。

2、綁定端口和IP地址: bind()

struct sockaddr_in addr;
addr.sin_family = AF_INET;//ipv4
addr.sin_addr.s_addr = htonl(INADDR_ANY);//綁定ip地址爲任意
addr.sin_port = htons(1234);//綁定端口號
int result = bind(serverScket,(const struct sockaddr *)&addr, sizeof(addr));
if(result == -1){
    NSLog(@"綁定出錯");
}else{
    NSLog(@"綁定成功");
}

我們使用 bind(int ,const sturct  sockeaddr *,int),來將scoket綁定到對應的IP地址和端口號上面,方便提供對應的服務。第一個參數表示我們上面的scoket的返回的int值,第二個參數是一個 結構體指針,並且類型是 sockaddr ,而IP地址和端口號就是封裝在其中,所以我們需要先創建一個此類型的結構體,我們這裏創建的是 sockaddr_in 類型的 addr,我們首先設置它的 sin_family屬性,這個屬性表示是IPv4,還是IPv6,第二個設置的屬性是 sin_addr下的s_addr,這個屬性表示的是IP地址,類型是in_addr_t 類型的,所以我們使用一個htonl()函數來轉化,由於是服務器,所以綁定IP地址爲任意,接下來綁定的端口號,使用 htons()來綁定端口號。

這個函數也會返回一個int值表示綁定是否成功。

3、監聽 : linsten()

 result = listen(serverScket, 5);
 if(result == -1){
    NSLog(@"監聽失敗");
 }else{
    NSLog(@"開始監聽");
 }

使用listen()函數來進行監聽,它接受兩個參數,第一個參數表示我們創建的socket,第二個參數表示這個服務器的最大承載量。

它的返回值同樣也描述狀態。

4、接收數據 : accept()

struct sockaddr_in c_addr;//用來保存客戶端的 addr(ip地址,端口號等)
    socklen_t len;
    char buff[1024];
    while (1) {
        //表示另一個客戶端的socket
        int newScoket = accept(serverScket, (struct sockaddr *)&c_addr, &len);
        if(newScoket == -1){
            NSLog(@"接受數據失敗");
        }else{
            NSLog(@"開始進行會話:%d",c_addr.sin_addr.s_addr);
            //接收數據
            size_t length = recv(newScoket, buff, 1024, 0);
            NSLog(@"接收了%zu個字節:%s",length,buff);
            //發送數據
            char * msg = "你好";
           ssize_t leng = send(newScoket,msg,strlen(msg),0);
            NSLog(@"成功發送給客戶端%zu字節:",leng);
        }
    }

我們使用accept()來接收監聽到客戶端的請求後發來的數據,這個函數有三個參數,第一個參數表示我們服務端的socket,第二個參數又是一個 struct sockaddr * 類型的變量,我們在外面創建一個 struct sockaddr_in 類型的變量 c_addr ,將這個變量的地址傳遞給accept函數,accept()就會給這個參數注入客戶端的 addr(ip地址,端口號),第三個參數表示注入的客戶端的 addr的長度,這個參數的意義就是便於內部實現尋址。這個函數返回狀態,我們根據這個狀態來判斷接收數據是否成功,如果成功,我們就可以接收數據和發送數據了

通過 recv()函數來接收數據,接收4個參數,客戶端的scoket,接收的數據放在哪裏(buff),buff的長度,最後一個參數默認放0。這個函數返回接收數據的長度。

通過send()函數來發送數據,接受4個參數,客戶端的scoket,發送的數據,發送數據的長度,最後一個參數默認放0.這個函數返回發送數據的長度。

 

 

下一片文章將介紹客戶端的scoket....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章