五、初始化 sk
分配完成 sk 後,另乙個重要的功能就是初始化它,sk 的成員相當複雜,其主要的初始化工作是在函式 sock_init_data()中完成的:
void sock_init_data(struct socket *sock, struct sock *sk)
else
sk->sk_sleep = null;
rwlock_init(&sk->sk_dst_lock);
rwlock_init(&sk->sk_callback_lock);
sk->sk_state_change = sock_def_wakeup;
sk->sk_data_ready = sock_def_readable;
sk->sk_write_space = sock_def_write_space;
sk->sk_error_report = sock_def_error_report;
sk->sk_destruct = sock_def_destruct;
sk->sk_sndmsg_page = null;
sk->sk_sndmsg_off = 0;
sk->sk_peercred.pid = 0;
sk->sk_peercred.uid = -1;
sk->sk_peercred.gid = -1;
sk->sk_write_pending = 0;
sk->sk_rcvlowat = 1;
sk->sk_rcvtimeo = max_schedule_timeout;
sk->sk_sndtimeo = max_schedule_timeout;
sk->sk_stamp.tv_sec = -1l;
sk->sk_stamp.tv_usec = -1l;
atomic_set(&sk->sk_refcnt, 1);
}sock 結構中,有三個重要的雙向佇列,分別是 sk_receive_queue、sk_write_queue和 sk_error_queue。從它們的名字就可以看出來其作用了。 佇列並非採用通用的 list_head 來維護,而是使用 skb_buffer 佇列:
struct sk_buff_head ;
這樣,佇列中指向的每乙個 skb_buffer,就是乙個資料報,分別是接收、傳送和投遞錯誤。
剩餘的就是初始化其它成員變數了。後面再來專門分析這些成員的作用。
inet_create 函式中,除了初始化 sk 成員的值,還有一部份**,是初始化乙個 inet的東東:
inet = inet_sk(sk);
inet->uc_ttl = -1;
inet->mc_loop = 1;
inet->mc_ttl = 1;
inet->mc_index = 0;
inet->mc_list = null;[/code]
inet 是乙個 struct inet_sock 結構型別,來看它的定義:
struct inet_sock
只留意它的第乙個成員就足夠了。
我們說 sock 是面向使用者態呼叫,而 sk 是面向核心驅動呼叫的,那 sk 是如何與協議棧互動的呢?對於每乙個型別的協議,為了與 sk 聯絡起來,都定義了乙個 struct ***_sock 結構,***是協議名,例如:
struct tcp_sock
struct udp_sock ;
struct raw_sock ;
很明顯,它們的結構定構是「af_inet一般屬性+自己的私有屬性」,因為它們的第乙個成員總是 inet。
呵呵,現在回頭來照一下起初在 af_inet.c 中,封裝協議註冊的時候,size成員,對於 tcp 而言:
.obj_size = sizeof(struct tcp_sock),
其它協議類似。
以 obj_size 來確定每個 slab 快取項分配的大小,所以,我們就可說,每次申請分配的,實際上是乙個 struct ***_sock 結構大小的結構。因為都是定義於上層結構的第乙個成員,可以使用強制型別轉換來使用這塊分配的記憶體空間。例如:
inet = inet_sk(sk);
static inline struct inet_sock *inet_sk(const struct sock *sk)
struct tcp_sock *tp = tcp_sk(sk);
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
ok,inet_create()執行完,乙個 socket 套接字基本上就建立完畢了,剩下的就是與檔案系統掛鉤,回到最初的 sys_socket()函式中來,它在呼叫完 sock_create()後,緊接著呼叫 sock_map_fd()函式:
int sock_map_fd(struct socket *sock)
sprintf(name, "[%lu]", sock_inode(sock)->i_ino);
this.name = name;
this.len = strlen(name);
this.hash = sock_inode(sock)->i_ino;
file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
if (!file->f_dentry)
file->f_dentry->d_op = &sockfs_dentry_operations;
d_add(file->f_dentry, sock_inode(sock));
file->f_vfsmnt = mntget(sock_mnt);
sock->file = file;
file->f_op = sock_inode(sock)->i_fop = &socket_file_ops;
file->f_mode = fmode_read | fmode_write;
file->f_flags = o_rdwr;
file->f_pos = 0; fd_install(fd, file);
} out:
return fd;
}這個函式的核心思想,在一開始,就已經分析過了。從程序的角度來講,乙個socket 套接字就是乙個特殊的,已開啟的檔案。前面分配好乙個 socket 後,這裡要做的就是將它與檔案系統拉上親戚關係。首先獲取乙個空閒的檔案描述符號和 file 結構。然後在檔案系統中分配乙個目錄項(d_alloc),使 其指向已經分配的 inode 節點(d_add),然後把其目錄項掛在 sockfs 檔案系統的根目錄之下。並且把目錄項的指標 d_op設定成指向 sockfs_dentry_operati,這個資料結構通過函式指標提供他與檔案路徑有關的操作:
static struct dentry_operations sockfs_dentry_operations = ;
最後一步,就是將 file 結構中的 f_op 和 sock 結構中的 i_fop 都指向 socket_file_ops,它是乙個函式指標集,指向了 socket面向檔案系統的使用者態呼叫的一些介面函式:
static struct file_operations socket_file_ops = ;
ok,到這裡,整個 socket 套接字的建立工作,就宣告完成了。
寫到這裡,可以為 socket 的建立下乙個小結了:
1、所謂建立socket,對核心而言,最重要的工作就是分配 sock 與 sk;
2、 sock 面向上層系統呼叫,主要是與檔案系統互動。通過程序的 current 指標的 files,結合建立 socket時返回的檔案描符述,可以找到內 核中對應的 struct file,再根據 file的 f_dentry可以找到對應的目錄項,而目錄項 struct dentry 中,有 d_inode 指標,指向與 sock 封裝在一起的 inode。sock 又與 sk指標互指,一一對應。在這串結構中,有兩個重要的函式集 指標,乙個是檔案系統 struct file 中的f_op指標,它指向了,對應的使用者態呼叫的read,write等操呼叫,但不支援open,另乙個是struct socket結構,即 sock 的ops 指標,它在 inet_create()中被置為 sock->ops = answer->ops; 指向具體協議型別的 ops;例如,inet_stream_ops、inet_dgram_ops 或者是 inet_sockraw_ops 等等。它用來支援上層的 socket 的其它 api 呼叫。
3、sk 面向核心協議棧,協議棧與它的介面資料結構是 struct protoname_sock,該結構中包含了一般性的 inet 結構和自己的私有成員,struct inet_sock 的第乙個成員就是乙個 sk 指標,而分配的 sk,實際上空間大小是 struct protoname_sock,所以,這三者可以通過強制型別轉換來獲取需要的指標。
java 基於TCP UDP協議的Socket程式設計
基於tcp協議的socket程式設計 服務端 public class serverlogin 6.關閉輸入流 scoket.shutdowninput 7.向客戶端發訊息 info 歡迎您,登陸成功!os.write info.getbytes bufferedreader.close 8.關閉輸...
SimpliciTI 網路協議棧
3.網路拓撲結構 4.節點型別 5.網路協議分層 5.2 nwk network 層 5.3 mrfi minimal rf inte ce 6.simpliciti 幀結構 7.網路協議應用 7.3 加入網路 join 0x03 7.4 安全 security 0x04 7.5 頻率捷變 freq...
《探尋linux協議棧》之一 linux協議棧概述
linux協議棧分層設計思想 linux分層究竟對報文做了什麼總結 本人所從事開發以來,一直在做資料面相關。資料面是乙個通訊裝置最終好不好用最直接的體現。因為乙個網路裝置,好不好用,資料 快不快,資料 穩定不穩定,全部都是使用者最直接體 現。所以工作八年以來,對linux核心協議棧業也積累了自己的一...