iT邦幫忙

0

iOS APP 開發 OC 第十一天,創建socket並連接伺服器

tags: OC 30 day

1. 導入頭文件

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

2. 創建 socket


創建時,看到系統提示要三個參數,但是實在是看不懂?
讓我們來google一下,剛好看到了這一篇翻轉工作室的文章

函數原型

int scoket(int domain,int type,int protocol); 

domain 參數

參數 domain 或稱為 family,是用來選擇使用哪一種通訊協定的家族系列,domain 可選擇下列之一:

  1. AF_UNIX:Unix Internet Protocol。此通訊家族並不是真正的網路通訊協定,而是用來作 Unix 作業系統中,各程序(Process)之間的通訊使用。一般使用在回授(Loopback)傳輸提供者,而其應用在主機內程序之間的通訊。
  2. AF_INET:Internet Protocol。此為 TCP/IP 的 Internet 通訊協定,傳輸提供者可能是 TCP 或 UDP,也是本章討論的重點。
  3. AF_NS:Xerox NS Protocol。此為 Xerox 公司發展的通訊協定。
  4. AF_IMPLINK:Interface Message Protocol。此為一種智慧型的分封交換節點協定,這些節點都是使用點對點的連接方式,一般使用在租用電話線路來作資料傳輸使用。(不在本章討論範圍)

其中『AF_』代表 Address Family,有些系統使用『PF_』(Protocol Family),兩者是相通的。domain 參數也如同 sockadd_in 資料結構中的 sin_family 參數一樣。

type 參數

參數 type 是設定該 Socket 的類型,可選擇下列類型之一:

  1. SOCK_STREAM:Stream Socket。傳輸提供者提供一個虛擬電路服務(TCP)。
  2. SOCK_DGRAM:Datagram Socket。提供電報傳輸服務(UDP)。
  3. SOCK_RAW:Raw Socket。通訊協定型態在傳輸層之下,譬如,在 AF_INET(傳輸層為 TCP 或 UDP)模式,SOCK_RAW 的通訊協定可以是 IP(Internet Protocol)或 ICMP(Internet Control Message Protocol)。
  4. SOCK_SEQPACKET:Sequenced Packet Socket。提供虛擬電路(TCP)並附有維護訊息的功能。

protocol 參數

參數 protocol 是在某一個 domain 之下,選擇所要哪一種協定。例如選定 AF_INET domain 系列時,所使用的協定可以是 TCP、UDP 或 IP中的一種。但當設定 domain 和 type 值時,對於所使用的協定大多已經指定完成,因此 protocol 的值一般都設定為0。但有一特殊情況,如果 Socket 的型態是 SOCK_RAW 時,必須在參數中指定它的上層協定為 TCP、UDP、IP 或 ICMP。

注意
type 與 protocol不可以隨意組合,如SOCKET_STREAM不可以跟IPPROTO_UDP組合。當地三個參數為0時,會自動選擇地=個參數類型對應默認協議。

大概了解以上的資料,我簡單整理出

//第一個參數 domain 協議 指定IPv4
//第二個參數 type socket的類型 流socket 數據報socket
//第三個參數 protocol 協議
//返回值 如果創建成功返回的是socket的描述符,失敗-1

我們來實踐看看吧

//1.    創建Socket

//第一個參數 domain 協議 指定IPv4
//第二個參數 type socket的類型 流socket 數據報socket
//第三個參數 protocol 協議
//返回值 如果創建成功返回的是socket的描述符,失敗-1
int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

3. 連接伺服器


connect要三個參數,但是依然是看不懂?。
於是就交給google大神吧。

參數一:套接字描述符
參數二:指向數據結構sockaddr的指針,其中包含目的端口與IP位址
參數三:參數二socketaddr的長度,可以通過sizeof(struct sockaddr)獲得

返回值
成功則返回0,失敗返回非0; 錯誤碼 GetLastError()

錯誤代碼

EBADF 參數sockfd 非合法socket處理代碼
EFAULT 參數serv_addr指針指向無法存取的內存空間
ENOTSOCK參數sockfd為一 文件描述詞,非socket。
EISCONN 參數sockfd的socket已是連線狀態
ECONNREFUSED 連線要求被server端拒絕。
ETIMEDOUT 企圖連線的操作超過限定時間仍未有響應。
ENETUNREACH 無法傳送數據包至指定的主機。
EAFNOSUPPORT sockaddr結構的sa_family不正確。
EALREADY socket為不可阻斷且先前的連線操作還未完成。

我們來實踐看看吧

//2.   連接伺服器
    //第一個參數 socket的描述符
    //第二個參數 結構體 ip地址與端口
    //第三個參數 結構體的長度 sizeof
    //返回值 成功0 失敗非0
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    connect(clientSocket, &addr, sizeof(addr));
    [self setUpViews];

然後會跳出一個警告

表示type不匹配,所以我們要轉型

    //2.   連接伺服器
    //第一個參數 socket的描述符
    //第二個參數 結構體 ip地址與端口
    //第三個參數 結構體的長度 sizeof
    //返回值 成功0 失敗非0
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    connect(clientSocket, (const struct sockaddr *)&addr, sizeof(addr));

完整的代碼:

    //1.    創建Socket
    
    //第一個參數 domain 協議 指定IPv4
    //第二個參數 type socket的類型 流socket 數據報socket
    //第三個參數 protocol 協議
    //返回值 如果創建成功返回的是socket的描述符,失敗-1
    int clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    
    //2.   連接伺服器
    //第一個參數 socket的描述符
    //第二個參數 結構體 ip地址與端口
    //第三個參數 結構體的長度 sizeof
    //返回值 成功0 失敗非0
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(12345);
    
    int result = connect(clientSocket, (const struct sockaddr *)&addr, sizeof(addr));
    
    if (result == 0){
        NSLog(@"成功");
    }else{
        NSLog(@"失敗");
    }
    

接下來連接伺服器就可以運行囉。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言