TCP/IP 協議概述 OSI 參考模型 TCP/IP 協議族 TCP UDP 三次握手協議 socket 概述 sockaddr sockaddr_in 存儲優先 地址格式轉化 名字地址轉化

                                       粉絲不過W

TCP/IP 協議概述

    OSI 參考模型及 TCP/IP 參考模型

          基於國際標準化組織(ISO), 共七層:應用層表示層會話層傳輸層網絡層數據鏈路層物理層

         將 TCP/IP 的 7層協議模型 簡化爲 4 層,便更有利於實現和使用

     OSI 模型和 TCP/IP 參考模型對應關係:

        網絡接口層:負責將二進制流轉換爲數據幀,並進行數據幀的發送接收

               note:  數據幀是獨立的網絡信息傳輸單元

        網絡層:負責將數據幀封裝成 IP 數據報,並運行必要的路由算法

        傳輸層:負責端對端之間的通信會話連接建立。傳輸協議的選擇根據數據傳輸方式而定

        應用層:負責應用程序的網絡訪問,這裏通過端口號來識別各個不同的進程

   TCP/IP 協議族

 

         ARP:用於獲得同一物理網絡中的硬件主機地址

         MPLS:多協議標籤協議

         IP:負責在主機和網絡之間尋址和路由數據包

         ICMP:用於發送報告有關數據包的傳送錯誤的協議

         IGMP:被 IP 主機用來向本地多路廣播路由器報告主機組成員的協議

         TCP:爲應用程序提供可靠的通信連接。適合於一次傳輸大批數據的情況。也適用於要求得到響應的應用程序

         UDP:提供了無連接通信,且不對傳送包進行可靠的保證。適合於一次傳輸少量數據可靠性則由應用層來負責

  TCP 和 UDP

    傳輸層 TCP 和 UDP 協議

     TCP

        概述

           TCP 向相鄰的高層提供服務

           由於 TCP 的上一層是應用層,所以 數據傳輸實現了從一個應用程序到另一個應用程序的數據傳遞

           打開 socket 來使用 TCP 服務,TCP 管理到其他 socket 的數據傳遞

       三次握手協議

           TCP 對話通過三次握手來初始化。目的:使數據段的發送和接收同步,告訴其他主機要一次可接收的數據量,並建立虛連接

            三次握手的簡單過程:

                 初始化主機,用一個同步標誌置位的數據段發出會話請求

                 接收主機通過發回下列數據段表示回覆:同步標誌置位、即將發送的數據段的起始字節的順序號、應答並帶有將收到的下一個數據段的字節順序號

                請求主機再回送一個數據段,並帶有確認順序號確認號

          TCP 三次握手協議流程:

           TCP 實體採用的基本協議:滑動窗口協議

          當發送方傳送一個數據報時,它將啓動計時器,當該數據報到達目的地後,接收方的 TCP 實體向回發送一個數據報,其中包含有一個確認序號,意思:要收到的下一個數據報的順序號。如 發送方的定時器在確認信息到達之前超時,那發送方會重發該數據報

      TCP 數據報頭

         TCP 數據報頭的格式:

          源端口、目的端口:16 位長。標識 遠端和本地的端口號

          序號:32 位長。標識 發送的數據報的順序

          確認號:32 位長。希望收到的下一個數據報的序列號

          TCP 頭長:4 位長。表明 TCP 頭中包含多少個 32 位字

          6 位未用

          ACK:ACK : 1 表明 確認號爲 合法。如 ACK 爲 0,那 數據報不包含確認信息,確認字段被省略

          PSH:表示 帶有 PUSH 標誌的數據。接收方請求數據報 一到 便可送往應用程序,不用等到緩衝區裝滿時才傳送

          RST:用於復位由於主機崩潰或其他原因而出現的錯誤的連接。還可以用於 拒絕非法的數據報或 拒絕連接請求

         SYN:用於建立連接

         FIN:用於釋放連接

         窗口大小:16 位長。窗口大小字段:在確認了字節之後還可以發送多少個字節

        校驗和:16 位長。是爲了確保高可靠性。校驗頭部、數據和僞 TCP 頭部之和

        可選項:0 個或多個 32 位字。包括最大 TCP 載荷,窗口比例、選擇重發數據報等選項

   UDP

        概述

          UDP :用戶數據報協議,一種無連接協議,因此不需要像 TCP 那樣通過三次握手來建立一個連接

       UDP 數據包頭

          

             源地址、目的地址:16 位長。標識出遠端和本地的端口號

            數據報的長度:包括報頭和數據部分在內的總的字節數,報頭的長度是固定,該域:計算可變長度的數據部分(別名:數據負載)

   協議的選擇

        對數據可靠性的要求

             對數據要求高可靠性的應用: TCP 協議,如驗證、密碼字段的傳送都是不允許出錯

             對數據的可靠性要求不那麼高的應用: UDP 傳送 

      應用的實時性

          由於 TCP 協議在傳送過程中要進行三次握手重傳確認等手段來保證數據傳輸的可靠性,所以TCP 協議會有較大的時延,因此不適合對實時性要求較高的應用,如 VOIP、視頻監控。

          UDP 協議:在這些應用中能發揮很好的作用

      網絡的可靠性

           TCP 協議的提出:解決網絡的可靠性問題,它通過各種機制來減少錯誤發生的概率

          在網絡狀況不是很好的情況下: TCP 協議,如 廣域網

          在網絡狀況很好的情況下: UDP 協議,減少網絡負荷,如 局域網

網絡基礎編程

   socket 概述

         socket 定義

               Linux 網絡編程通過 socket 接口來進行

              socket 接口:一種特殊的 I/O,一種文件描述符

              每一個 socket 都用一個半相關描述{ 協議,本地地址、本地端口 }來表示

             該函數返回一個整型的 socket 描述符,隨後的連接建立、數據傳輸等操作都是通過 socket 來實現

             一個完整的套接字用一個相關描述{ 協議,本地地址、本地端口、遠程地址、遠程端口 }

       socket 類型

            流式 socket(SOCK_STREAM)

               流式套接字提供可靠的、面向連接的通信流;使用 TCP 協議,從而保證了數據傳輸的正確性和順序性

          數據報 socket(SOCK_DGRAM)

               數據報套接字定義了一種無連接的服務,數據通過相互獨立的報文進行傳輸,是無序的,且不保證是可靠、無差錯

         原始 socket

              原始套接字允許對底層協議如 IP 或 ICMP 進行直接訪問,它功能強大但使用不便,主要用於一些協議的開發

   地址及順序處理

        數據結構介紹

/* 等效,可相互轉化 */
struct sockaddr
{
    unsigned short sa_family; /* 地址族 */
    char sa_data[14]; /* 14 字節的協議地址,含該 socket 的 IP 地址、端口號 */
};

struct sockaddr_in
{
    short int sa_family; /* 地址族 */
    unsigned short int sin_port; /* 端口號 */
    struct in_addr sin_addr; /* IP 地址 */
    unsigned char sin_zero[8]; /*填充 0 以保持與 struct sockaddr 同樣大小*/
};

       結構字段

#include <netinet/in.h>

/*
 *AF_INET: IPv4 協議
 *AF_INET6:IPv6 協議
 *AF_LOCAL:UNIX 域協議
 *AF_LINK: 鏈路地址協議
 *AF_KEY:  密鑰套接字(socket)
 */
unsigned short sa_family;

    數據存儲優先順序

          函數說明

            計算機數據存儲有兩種字節優先順序:高位字節優先低位字節優先

           Internet 上數據以高位字節優先順序在網絡上傳輸

          兩個字節存儲優先順序進行相互轉化時,需用到:htons、ntohs、htonl、ntohl

           h 代表 host,n 代表 network,s 代表 short,l 代表 long

           通常 16 位的 IP 端口號用 s 代表,而 IP 地址用 l 來代表

#include <netinet/in.h>

/*
 *parameter:
 *  host16bit:主機字節序的 16bit 數據
 *  host32bit:主機字節序的 32bit 數據
 *  net16bit: 網絡字節序的 16bit 數據
 *  net32bit: 網絡字節序的 32bit 數據
 *return:
 *  成功:轉換的字節序
 *  出錯:-1
 */
uint16_t htons(unit16_t host16bit)
uint32_t htonl(unit32_t host32bit)
uint16_t ntohs(unit16_t net16bit)
uint32_t ntohs(unit32_t net32bit)

    地址格式轉化

         函數說明

            用戶在表達地址時採用的是點分十進制表示的數值(或 以冒號分開的十進制IPv6 地址),而 使用的 socket 編程中所使用的是二進制值

#include <arpa/inet.h>

/*
 *function:
 *  點分十進制地址映射爲二進制地址
 *parameter:
 *  family:
 *    AF_INET: IPv4 協議
 *    AF_INET6:IPv6 協議
 *  strptr:  轉化的值
 *  addrptr: 轉化後的地址
 *return:
 *  成功:0
 *  失敗:-1
 */
int inet_pton(int family, const char *strptr, void *addrptr)

/*
 *function:
 *  二進制地址映射爲點分十進制地址
 *parameter:
 *  family:
 *    AF_INET: IPv4 協議
 *    AF_INET6:IPv6 協議
 *  addrptr:轉化後的地址
 *  strptr: 要轉化的值
 *  Len:    轉化後值的大小
 *return:
 *  成功:0
 *  失敗:-1
 */
int inet_ntop(int family, void *addrptr, char *strptr, size_t len)

     名字地址轉化

          函數說明

             實現 IPv4 和 IPv6 的地址和主機名之間的轉化

struct hostent
{
    char *h_name;        /* 正式主機名 */
    char **h_aliases;    /* 主機別名 */
    int h_addrtype;      /* 地址類型 */
    int h_length;        /* 地址長度 */
    char **h_addr_list;  /* 指向 IPv4 或 IPv6 的地址指針數組 */
};
#include <netdb.h>

/*
 *ai_flags:
 *  AI_PASSIVE:  該套接口是用作被動地打開
 *  AI_CANONNAME:通知 getaddrinfo 函數返回主機的名字
 *family:
 *  AF_INET: IPv4 協議
 *  AF_INET6:IPv6 協議
 *  AF_UNSPE:IPv4 或 IPv6 均可
 *ai_socktype:
 *  SOCK_STREAM:字節流套接字 socket(TCP)
 *  SOCK_DGRAM: 數據報套接字 socket(UDP)
 *ai_protocol:
 *  IPPROTO_IP:  IP 協議
 *  IPPROTO_IPV4:IPv4 協議
 *  IPPROTO_IPV6:IPv6 協議
 *  IPPROTO_UDP: UDP
 *  IPPROTO_TCP: TCP
 *note:
 *  服務器端, ai_flags: AI_PASSIVE,主機名 nodename: NULL
 *  客戶端,,ai_flags != AI_PASSIVE,且 主機名 nodename 和服務名 servname(端口)!= 空
 */
struct addrinfo
{
    int ai_flags;             /* AI_PASSIVE,AI_CANONNAME */
    int ai_family;            /* 地址族 */
    int ai_socktype;          /* socket 類型 */
    int ai_protocol;          /* 協議類型 */
    size_t ai_addrlen;        /* 地址長度 */
    char *ai_canoname;        /* 主機名 */
    struct sockaddr *ai_addr; /* socket 結構體 */
    struct addrinfo *ai_next; /* 下一個指針鏈表 */
};

      函數格式 

#include <netdb.h>

/*
 *function:
 *  主機名轉化爲 IP 地址
 *parameter:
 *  hostname:主機名
 *return:
 *  成功:hostent 類型指針
 *  失敗:-1
 */
struct hostent *gethostbyname(const char *hostname)
#include <netdb.h>

/*
 *function:
 *  自動識別 IPv4 地址和 IPv6 地址
 *parameter:
 *  hostname:主機名
 *  service: 服務名或十進制的串口號字符串
 *  hints:   服務線索函數傳入值
 *  result:  返回結果
 *return:
 *  成功:0
 *  出錯:-1
 */
int getaddrinfo(const char *hostname,
                const char *service,
                const struct addrinfo *hints,
                struct addrinfo **result)

例:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>

int main()
{
    struct addrinfo hints, *res = NULL;
    int rc;

    memset(&hints, 0, sizeof(hints));

    /*設置 addrinfo 結構體中各參數*/
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;

    /*調用 getaddinfo 函數*/
    rc = getaddrinfo("127.0.0.1", "123", &hints, &res);
    if(rc != 0)
    {
        perror("getaddrinfo");
        exit(1);
    }
    else
    {
        printf("getaddrinfo success\n");
    }
}

 

生成結果

生成結果

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