中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何深入理解TCP/IP協議的socket實現

發布時間:2021-11-23 22:08:15 來源:億速云 閱讀:196 作者:柒染 欄目:大數據

這篇文章給大家介紹如何深入理解TCP/IP協議的socket實現,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

socket大家都知道是用于網絡通信的,也知道他是ip和端口的組合。但是很多同學可能不是很清楚socket的原理和實現。下面我們深入理解一下socket到底是什么。
    我們回憶一下socket編程的步驟,不管是客戶端還是服務端,第一個調的函數都是socket。我們就從這個函數的實現開始,看看一個socket到底是什么。

// 新建一個socket結構體,并且創建一個下層的sock結構體,互相關聯
static int sock_socket(int family, int type, int protocol)
{
    int i, fd;
    struct socket *sock;
    struct proto_ops *ops;

    // 找到對應的協議族,比如unix域、ipv4
    for (i = 0; i < NPROTO; ++i) 
    {   // 從props數組中找到family協議對應的操作函數集,props由系統初始化時sock_register進行操作
        if (pops[i] == NULL) continue;
        if (pops[i]->family == family) 
            break;
    }

    if (i == NPROTO) 
    {
          return -EINVAL;
    }
    // 函數集
    ops = pops[i];

    // 檢查一下類型
    if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
        type != SOCK_SEQPACKET && type != SOCK_RAW &&
        type != SOCK_PACKET) || protocol < 0)
            return(-EINVAL);

    // 分配一個新的socket結構體
    if (!(sock = sock_alloc())) 
    {
        ...
    }
    // 設置類型和操作函數集
    sock->type = type;
    sock->ops = ops;
    if ((i = sock->ops->create(sock, protocol)) < 0) 
    {
        sock_release(sock);
        return(i);
    }
    // 返回一個新的文件描述符
    if ((fd = get_fd(SOCK_INODE(sock))) < 0) 
    {
        sock_release(sock);
        return(-EINVAL);
    }

    return(fd);
}
 

我們從上到下,逐步分析這個過程。
1 根據傳的協議類型,找到對應的函數集,因為不同的協議族他的底層操作是不一樣的。
2 分配一個socket結構體。定義如下。我們大概了解一下字段就行。

struct socket {
  short            type;       /* SOCK_STREAM, ...     */
  socket_state        state;
  long            flags;
  struct proto_ops    *ops;   
  // 這個字段要記一下    
  void            *data;      
  struct socket        *conn;      
  struct socket        *iconn;     
  struct socket        *next;
  struct wait_queue    **wait;     
  struct inode        *inode;
  struct fasync_struct  *fasync_list;    
};

struct socket *sock_alloc(void)
{
    struct inode * inode;
    struct socket * sock;
    // 獲取一個可用的inode節點
    inode = get_empty_inode();
    if (!inode)
        return NULL;
    // 初始化某些字段
    inode->i_mode = S_IFSOCK;
    inode->i_sock = 1;// socket文件
    inode->i_uid = current->uid;
    inode->i_gid = current->gid;
    // 指向inode的socket結構體,初始化inode結構體的socket結構體
    sock = &inode->u.socket_i;
    sock->state = SS_UNCONNECTED;
    sock->flags = 0;
    sock->ops = NULL;
    sock->data = NULL;
    sock->conn = NULL;
    sock->iconn = NULL;
    sock->next = NULL;
    sock->wait = &inode->i_wait;
    // 互相引用
    sock->inode = inode;        /* "backlink": we could use pointer arithmetic instead */
    sock->fasync_list = NULL;
    // socket數加一
    sockets_in_use++;
    // 返回新的socket結構體,他掛載在inode中
    return sock;
}
 

sock_alloc首先分配了一個inode,inode節點里有一個socket結構體,然后初始化socket結構體的一些字段,并把他的地址返回。

3 這時候我們拿到一個socket結構體。接著調create函數(省略了部分代碼)。

// 創建一個sock結構體,和socket結構體互相關聯
static int inet_create(struct socket *sock, int protocol)
{
    struct sock *sk;
    struct proto *prot;
    int err;
    // 分配一個sock結構體
    sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
    switch(sock->type) 
    {
        case SOCK_STREAM:
            protocol = IPPROTO_TCP;
            // 函數集
            prot = &tcp_prot;
            break;

        case SOCK_DGRAM:
            protocol = IPPROTO_UDP;
            prot=&udp_prot;
            break;

    }
    // sock結構體的socket字段指向上層的socket結構體
    sk->socket = sock;
    // 省略一堆對sock結構體的初始化代碼
}
 

我們發現創建一個socket的時候,申請了一個socket結構體,同時也申請了一個sock結構體。為什么需要兩個結構體,并且這兩個結構體關聯在一起呢?這要說到網絡協議的復雜性,而這個設計就是linux對這個復雜性的解決方案。我們回頭看看socket函數的參數。

socket(int family, int type, int protocol)
 

family是協議簇,比如unix域、ipv4、ipv6,type是在第一個參數的基礎上的子分類。比如ipv4下有tcp、udp、raw、packet。protocol對tcp、udp沒用,對raw、packet的話是標記上層協議類型。這好比一棵樹一樣,從根節點開始,有很多分支。socket結構體是整個網絡協議實現的最上層結構,是第一層抽象。根據協議簇的不同,有不同的實現函數,在同一協議簇下,也有不同的子分類,比如ipv4下有tcp、udp等。不同子類具體的邏輯也不一樣。即數據結構和算法都不一樣。所以socket結構體有一個data字段,他是自定義的,對于ipv4的實現,他是指向一個sock結構體,對于unix域的實現,unix_proto_data結構體。這就解決了不同協議簇(family)不同實現的問題。那對于同一協議簇下的不同子類型,又如何實現呢?比如ipv4下的tcp、udp。linux給出的方案是在sock結構體中定義一個字段,根據子類型type的值,指向不同的底層協議函數集。

如何深入理解TCP/IP協議的socket實現  
在這里插入圖片描述

在申請完sock結構體并且和socket結構體互相關聯后。這時候我們拿到了一個inode,一個socket結構體,一個sock結構體。然后根據inode拿到一個file和fd文件描述符。最后返回fd給用戶。內容結構圖如下。  
 
如何深入理解TCP/IP協議的socket實現  
在這里插入圖片描述

這就是socket函數返回后的內存結構體。后續我們調用bind,listen等等函數,傳入fd,系統就會根據上面圖的指向,一直找到tcp函數集,執行對應的函數,對于udp也是一樣,不同是tcp函數集變成udp函數集。

關于如何深入理解TCP/IP協議的socket實現就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

磐安县| 紫云| 河北区| 广德县| 阿城市| 泰来县| 普定县| 高密市| 肥城市| 东兴市| 同江市| 邹城市| 鄯善县| 庄河市| 长乐市| 东莞市| 兴宁市| 榕江县| 手游| 潞城市| 横峰县| 常宁市| 博兴县| 犍为县| 宜黄县| 南宫市| 青铜峡市| 白河县| 谷城县| 德兴市| 玛沁县| 双牌县| 伊宁县| 五大连池市| 石泉县| 天台县| 潼南县| 洛浦县| 青阳县| 托克逊县| 张家港市|