sock結構和socket結構詳細解釋

來源:互聯網
上載者:User

前段時間看了一些 TCP/IP協議棧方面的東西,有很多東西想寫,沒時間 ,以後補上


//************************************************************************** 

/* 1、每一個開啟的檔案、socket等等都用一個file資料結構代表,這樣檔案和socket就通過inode->u(union)中的各個成員來區別: 
struct inode { 
..................... 
union { 
struct ext2_inode_info ext2_i; 
struct ext3_inode_info ext3_i; 
struct socket socket_i; 
..................... 
} u; }; 
2、每個socket資料結構都有一個sock資料結構成員,sock是對socket的擴充,兩者一一對應,socket->sk指向對應的sock,sock->socket 
指向對應的socket; 
3、socket和sock是同一事物的兩個側面,為什麼不把兩個資料結構合并成一個呢?這是因為socket是inode結構中的一部分,即把inode結 
構內部的一個union用作socket結構。由於插口操作的特殊性,這個資料結構中需要有大量的結構成分,如果把這些成分全部放到socket 
結構中,則inode結構中的這個union就會變得很大,從而inode結構也會變得很大,而對於其他檔案系統這個union是不需要這麼大的, 
所以會造成巨大浪費,系統中使用inode結構的數量要遠遠超過使用socket的數量,故解決的辦法就是把插口分成兩部分,把與檔案系 
統關係密切的放在socket結構中,把與通訊關係密切的放在另一個單獨結構sock中; 
*/ 

struct socket 

socket_state state; // 該state用來表明該socket的目前狀態 
typedef enum { 
SS_FREE = 0, /* not allocated */ 
SS_UNCONNECTED, /* unconnected to any socket */ 
SS_CONNECTING, /* in process of connecting */ 
SS_CONNECTED, /* connected to socket */ 
SS_DISCONNECTING /* in process of disconnecting */ 
} socket_state; 
unsigned long flags; //該成員可能的值如下,該標誌用來設定socket是否正在忙碌 
#define SOCK_ASYNC_NOSPACE 0 
#define SOCK_ASYNC_WAITDATA 1 
#define SOCK_NOSPACE 2 
struct proto_ops *ops; //依據協議邦定到該socket上的特定的協議族的操作函數指標,例如IPv4 TCP就是inet_stream_ops 
struct inode *inode; //表明該socket所屬的inode 
struct fasync_struct *fasync_list; //非同步喚醒隊列 
struct file *file; //file回指指標 
struct sock *sk; //sock指標 
wait_queue_head_t wait; //sock的等待隊列,在TCP需要等待時就sleep在這個隊列上 
short type; //表示該socket在特定協議族下的類型例如SOCK_STREAM, 
unsigned char passcred; //在TCP分析中無須考慮 
}; 

//************************************************************************** 

struct sock { 
/* socket用來對進入的包進行匹配的5大因素 */ 
__u32 daddr; // dip,Foreign IPv4 addr 
__u32 rcv_saddr; // 記錄通訊端所綁定的地址 Bound local IPv4 addr 
__u16 dport; // dport 
unsigned short num; /* 通訊端所在的連接埠號碼, 連接埠號碼小於1024的為特權連接埠, 只有特權使用者才能綁定,當使用者指定的端 
口號為零時, 系統將提供一個未指派的使用者連接埠,如果對於raw socket的話,該num又可以用來 
儲存socket(int family, int type, int protocol)中的protocol,而不是連接埠號碼了;在bind時候,會首先 
將邦定的源連接埠號碼賦予該成員,最終sport成員從該成員出擷取源連接埠號碼*/ 
int bound_dev_if; // Bound device index if != 0 

/* 主hash鏈,系統已指派的連接埠用tcp_hashinfo.__tcp_bhash來索引, 索引槽結構為tcp_bind_hashbucket, 連接埠綁定結構用tcp_bind_bucket描述, 
它包含指向綁定到該連接埠通訊端的指標(owners), 通訊端的sk->prev指標指向該綁定結構 
*/ 
struct sock *next; 
struct sock **pprev; 
/* sk->bind_next和sk->bind_pprev用來描述綁定到同一連接埠的通訊端,例如http伺服器 */ 
struct sock *bind_next; 
struct sock **bind_pprev; 
struct sock *prev; 

volatile unsigned char state, zapped; // Connection state,zapped在TCP分析中無須考慮 
__u16 sport; // 源連接埠,見num 

unsigned short family; // 協議族,例如PF_INET 
unsigned char reuse; // 地址是否可重用,只有RAW才使用 
unsigned char shutdown; // 判斷該socket串連在某方向或者雙向方向上都已經關閉 
#define SHUTDOWN_MASK 3 
#define RCV_SHUTDOWN 1 
#define SEND_SHUTDOWN 2 
atomic_t refcnt; // 引用計數 
socket_lock_t lock; // 鎖標誌, 每個socket都有一個自旋鎖,該鎖在使用者上下文和非強制中斷處理時提供了同步機制 
typedef struct { 
spinlock_t slock; 
unsigned int users; 
wait_queue_head_t wq; 
} socket_lock_t; 
wait_queue_head_t *sleep; // Sock所屬線程的自身休眠等待隊列 
struct dst_entry *dst_cache; // 目的地的路由緩衝 
rwlock_t dst_lock; // 為該socket賦dst_entry值時的鎖 

/* sock的收發都是要佔用記憶體的,即發送緩衝區和接收緩衝區。 系統對這些記憶體的使用是有限制的。 通常,每個sock都會從配額裡 
預先分配一些,這就是forward_alloc, 具體分配時: 
1)比如收到一個skb,則要計算到rmem_alloc中,並從forward_alloc中扣除。 接收處理完成後(如使用者態讀取),則釋放skb,並利 
用tcp_rfree()把該skb的記憶體反還給forward_alloc。 
2)發送一個skb,也要暫時放到發送緩衝區,這也要計算到wmem_queued中,並從forward_alloc中扣除。真正發送完成後,也釋放 
skb,並反還forward_alloc。 當從forward_alloc中扣除的時候,有可能forward_alloc不夠,此時就要調用tcp_mem_schedule()來增 
加forward_alloc,當然,不是隨便想加就可以加的,系統對整個TCP的記憶體使用量有總的限制,即sysctl_tcp_mem[3]。也對每個sock 
的記憶體使用量分別有限制,即sysctl_tcp_rmem[3]和sysctl_tcp_wmem[3]。只有滿足這些限制(有一定的靈活性),forward_alloc才 
能增加。 當發現記憶體緊張的時候,還會調用tcp_mem_reclaim()來回收forward_alloc預先分配的配額。 
*/ 
int rcvbuf; // 接受緩衝區的大小(按位元組) 
int sndbuf; // 發送緩衝區的大小(按位元組) 
atomic_t rmem_alloc; // 接受隊列中存放的資料的位元組數 
atomic_t wmem_alloc; // 發送隊列中存放的資料的位元組數 
int wmem_queued; // 所有已經發送的資料的總位元組數 
int forward_alloc; // 預分配剩餘位元組數 

struct sk_buff_head receive_queue; // 接受隊列 
struct sk_buff_head write_queue; // 發送隊列 
atomic_t omem_alloc; // 在TCP分析中無須考慮 * "o" is "option" or "other" */ 

__u32 saddr; /* 指真正的發送地址,這裡需要注意的是,rcv_saddr是記錄通訊端所綁定的地址,其可能是廣播或者 
多播,對於我們要發送的包來說,只能使用介面的IP地址,而不能使用廣播或者多播地址 */ 
unsigned int allocation; // 分配該sock之skb時選擇的模式,GFP_ATOMIC還是GFP_KERNEL等等 

volatile char dead, // tcp_close.tcp_listen_stop.inet_sock_release調用sock_orphan將該值置1,表示該socket已經和進程分開,變成孤兒 
done, // 用於判斷該socket是否已經收到 fin,如果收到則將該成員置1 
urginline, // 如果該值被設定為1,表示將緊急資料放於普通資料流中一起處理,而不在另外處理 
keepopen, // 是否啟動保活定時器 
linger, // lingertime一起,指明了close()後保留的時間 
destroy, // 在TCP分析中無須考慮 
no_check, // 是否對發出的skb做校正和,僅對UDP有效 
broadcast, // 是否允許廣播,僅對UPD有效 
bsdism; // 在TCP分析中無須考慮 
unsigned char debug; // 在TCP分析中無須考慮 
unsigned char rcvtstamp; // 是否將收到skb的時間戳記發送給app 
unsigned char use_write_queue; // 在init中該值被初始化為1 
unsigned char userlocks; // 包括如下幾種值的組合,從而改變收包等操作的執行順序 
#define SOCK_SNDBUF_LOCK 1 
#define SOCK_RCVBUF_LOCK 2 
#define SOCK_BINDADDR_LOCK 4 
#define SOCK_BINDPORT_LOCK 8 
int route_caps; // 指示本sock用到的路由的資訊 
int proc; // 儲存使用者線程的pid 
unsigned long lingertime; // lingertime一起,指明了close()後保留的時間 
int hashent; // 存放4元的hash值 
struct sock *pair; // 在TCP分析中無須考慮 

struct { //當sock被鎖定時,收到的資料先放在這裡 
struct sk_buff *head; 
struct sk_buff *tail; 
} backlog; 

rwlock_t callback_lock; // sock相關函數內部操作的保護鎖 
struct sk_buff_head error_queue; // 錯誤判文的隊列,很少使用 
struct proto *prot; // 例如指向tcp_prot 

union { // 私人TCP相關資料儲存 
struct tcp_opt af_tcp; 
............. 
} tp_pinfo; 

int err, // 儲存各種錯誤,例如ECONNRESET Connection reset by peer,從而會影響到後續流程的處理 
err_soft; // 儲存各種軟性錯誤,例如EPROTO Protocol error,從而會影響到後續流程的處理 
unsigned short ack_backlog; // 當前已經accept的數目 
unsigned short max_ack_backlog; // 最大可accept的數目 
__u32 priority; /* Packet queueing priority,Used to set the TOS field. Packets with a higher priority may be processed first, depending on the device’s queueing discipline. See SO_PRIORITY */ 
unsigned short type; // 例如SOCK_STREAM,SOCK_DGRAM或者SOCK_RAW等 
unsigned char localroute; // Route locally only if set – set by SO_DONTROUTE option. 
unsigned char protocol; // socket(int family, int type, int protocol)中的protocol 
struct ucred peercred; // 在TCP分析中無須考慮 
int rcvlowat; /* 聲明在開始發送 資料 (SO_SNDLOWAT) 或正在接收資料的使用者 (SO_RCVLOWAT) 傳遞資料之 
前緩衝區內的最小位元組數. 在 Linux 中這兩個值是不可改變的, 固定為 1 位元組. */ 
long rcvtimeo; // 接收時的逾時設定, 並在逾時時報錯 
long sndtimeo; // 發送時的逾時設定, 並在逾時時報錯 

union { // 私人inet相關資料儲存 
struct inet_opt af_inet; 
................. 
} protinfo; 

/* the timer is used for SO_KEEPALIVE (i.e. sending occasional keepalive probes to a remote site – by default, set to 2 hours in 
stamp is simply the time that the last packet was received. */ 
struct timer_list timer; 
struct timeval stamp; 
struct socket *socket; // 對應的socket 
void *user_data; // 私人資料,在TCP分析中無須考慮 

/* The state_change operation is called whenever the status of the socket is changed. Similarly, data_ready is called 
when data have been received, write_space when free memory available for writing has increased and error_report 
when an error occurs, backlog_rcv when socket locked, putting skb to backlog, destruct for release this sock*/ 
void (*state_change)(struct sock *sk); 
void (*data_ready)(struct sock *sk,int bytes); 
void (*write_space)(struct sock *sk); 
void (*error_report)(struct sock *sk); 
int (*backlog_rcv) (struct sock *sk, struct sk_buff *skb); 
void (*destruct)(struct sock *sk); 
}; 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.