您好,登錄后才能下訂單哦!
這篇文章給大家介紹如何深入理解TCP/IP協(xié)議的socket實現(xiàn),內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
socket大家都知道是用于網(wǎng)絡(luò)通信的,也知道他是ip和端口的組合。但是很多同學(xué)可能不是很清楚socket的原理和實現(xiàn)。下面我們深入理解一下socket到底是什么。
我們回憶一下socket編程的步驟,不管是客戶端還是服務(wù)端,第一個調(diào)的函數(shù)都是socket。我們就從這個函數(shù)的實現(xiàn)開始,看看一個socket到底是什么。
// 新建一個socket結(jié)構(gòu)體,并且創(chuàng)建一個下層的sock結(jié)構(gòu)體,互相關(guān)聯(lián)
static int sock_socket(int family, int type, int protocol)
{
int i, fd;
struct socket *sock;
struct proto_ops *ops;
// 找到對應(yīng)的協(xié)議族,比如unix域、ipv4
for (i = 0; i < NPROTO; ++i)
{ // 從props數(shù)組中找到family協(xié)議對應(yīng)的操作函數(shù)集,props由系統(tǒng)初始化時sock_register進(jìn)行操作
if (pops[i] == NULL) continue;
if (pops[i]->family == family)
break;
}
if (i == NPROTO)
{
return -EINVAL;
}
// 函數(shù)集
ops = pops[i];
// 檢查一下類型
if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
type != SOCK_SEQPACKET && type != SOCK_RAW &&
type != SOCK_PACKET) || protocol < 0)
return(-EINVAL);
// 分配一個新的socket結(jié)構(gòu)體
if (!(sock = sock_alloc()))
{
...
}
// 設(shè)置類型和操作函數(shù)集
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 根據(jù)傳的協(xié)議類型,找到對應(yīng)的函數(shù)集,因為不同的協(xié)議族他的底層操作是不一樣的。
2 分配一個socket結(jié)構(gòu)體。定義如下。我們大概了解一下字段就行。
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節(jié)點
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結(jié)構(gòu)體,初始化inode結(jié)構(gòu)體的socket結(jié)構(gòu)體
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數(shù)加一
sockets_in_use++;
// 返回新的socket結(jié)構(gòu)體,他掛載在inode中
return sock;
}
sock_alloc首先分配了一個inode,inode節(jié)點里有一個socket結(jié)構(gòu)體,然后初始化socket結(jié)構(gòu)體的一些字段,并把他的地址返回。
3 這時候我們拿到一個socket結(jié)構(gòu)體。接著調(diào)create函數(shù)(省略了部分代碼)。
// 創(chuàng)建一個sock結(jié)構(gòu)體,和socket結(jié)構(gòu)體互相關(guān)聯(lián)
static int inet_create(struct socket *sock, int protocol)
{
struct sock *sk;
struct proto *prot;
int err;
// 分配一個sock結(jié)構(gòu)體
sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
switch(sock->type)
{
case SOCK_STREAM:
protocol = IPPROTO_TCP;
// 函數(shù)集
prot = &tcp_prot;
break;
case SOCK_DGRAM:
protocol = IPPROTO_UDP;
prot=&udp_prot;
break;
}
// sock結(jié)構(gòu)體的socket字段指向上層的socket結(jié)構(gòu)體
sk->socket = sock;
// 省略一堆對sock結(jié)構(gòu)體的初始化代碼
}
我們發(fā)現(xiàn)創(chuàng)建一個socket的時候,申請了一個socket結(jié)構(gòu)體,同時也申請了一個sock結(jié)構(gòu)體。為什么需要兩個結(jié)構(gòu)體,并且這兩個結(jié)構(gòu)體關(guān)聯(lián)在一起呢?這要說到網(wǎng)絡(luò)協(xié)議的復(fù)雜性,而這個設(shè)計就是linux對這個復(fù)雜性的解決方案。我們回頭看看socket函數(shù)的參數(shù)。
socket(int family, int type, int protocol)
family是協(xié)議簇,比如unix域、ipv4、ipv6,type是在第一個參數(shù)的基礎(chǔ)上的子分類。比如ipv4下有tcp、udp、raw、packet。protocol對tcp、udp沒用,對raw、packet的話是標(biāo)記上層協(xié)議類型。這好比一棵樹一樣,從根節(jié)點開始,有很多分支。socket結(jié)構(gòu)體是整個網(wǎng)絡(luò)協(xié)議實現(xiàn)的最上層結(jié)構(gòu),是第一層抽象。根據(jù)協(xié)議簇的不同,有不同的實現(xiàn)函數(shù),在同一協(xié)議簇下,也有不同的子分類,比如ipv4下有tcp、udp等。不同子類具體的邏輯也不一樣。即數(shù)據(jù)結(jié)構(gòu)和算法都不一樣。所以socket結(jié)構(gòu)體有一個data字段,他是自定義的,對于ipv4的實現(xiàn),他是指向一個sock結(jié)構(gòu)體,對于unix域的實現(xiàn),unix_proto_data結(jié)構(gòu)體。這就解決了不同協(xié)議簇(family)不同實現(xiàn)的問題。那對于同一協(xié)議簇下的不同子類型,又如何實現(xiàn)呢?比如ipv4下的tcp、udp。linux給出的方案是在sock結(jié)構(gòu)體中定義一個字段,根據(jù)子類型type的值,指向不同的底層協(xié)議函數(shù)集。
關(guān)于如何深入理解TCP/IP協(xié)議的socket實現(xiàn)就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。