您的位置:首页 > 理论基础 > 计算机网络

TCP/IP工作流的开始 socket创建4

2016-12-25 22:01 393 查看

tcp_v4_init_sock函数的剩下部分

继续回到tcp_v4_init_sock。

1873 tp->reordering = sysctl_tcp_reordering;

又是struct tcp_sock的一个成员变量reordering,意思为重新排序。这里只是设置一个初值,其具体含义,现在还不知道。从数值来源变量名称中,可以看到这个是可以通过用户来控制的一个选项。

1874 icsk->icsk_ca_ops = &tcp_init_congestion_ops;

这个变量tcp_init_congestion_ops看起来有点熟悉,之前在tcp_init函数(见TCP/IP协议栈初始化(八) TCP马上准备进入状态 )中说过,当时是注册了一个tcp_reno的变量。从名称上来看2个都是用来实现TCP拥堵控制的。两个变量都是在net/ipv4/tcp_cong.c中定义,相邻。

376 struct tcp_congestion_ops tcp_reno = {
377     .flags      = TCP_CONG_NON_RESTRICTED,
378     .name       = "reno",
379     .owner      = THIS_MODULE,
380     .ssthresh   = tcp_reno_ssthresh,
381     .cong_avoid = tcp_reno_cong_avoid,
382     .min_cwnd   = tcp_reno_min_cwnd,
383 };
389 struct tcp_congestion_ops tcp_init_congestion_ops  = {
390     .name       = "",
391     .owner      = THIS_MODULE,
392     .ssthresh   = tcp_reno_ssthresh,
393     .cong_avoid = tcp_reno_cong_avoid,
394     .min_cwnd   = tcp_reno_min_cwnd,
395 };


仔细一看,原来所有的变量成员都一样。这:<

1876 sk->sk_state = TCP_CLOSE;

设置TCP连接的状态是TCP_CLOSE,因为socket的创建流程还没有进行完毕。

1878 sk->sk_write_space = sk_stream_write_space;

1879 sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);

初始化了struct sock的写空间回调函数,TCP执行流量控制,不可能用户产生多少数据都能快速发送出去,所以这里为sock配置了写队列,并且给它添加了回调函数,当队列中有空间时,就可以通知用户继续写入数据。并设置了struct sock *sk要使用写队列。

1881 icsk->icsk_af_ops = &ipv4_specific;

1882 icsk->icsk_sync_mss = tcp_sync_mss;

设置socket关联的struct inet_connetion_sock的成员变量icsk_af_ops。同样af是代表address family。与地址协议族相关的调用接口。这里被初始化为ipv4_specific。这个变量定义在net/ipv4/tcp_ipv4.c中。其成员函数,现在还没有遇到。先不说。

1882初始化的成员变量是,用来在连接建立时同步MSS。MSS就是最大报文段长度,是MTU减去IP层和TCP首部后的长度。

1883-1885 是允许编译内核时,由TCP层来计算校验各。这里不展开说。

1887 sk->sk_sndbuf = sysctl_tcp_wmem[1];

1888 sk->sk_rcvbuf = sysctl_tcp_rmem[1];

初始化每个sk的接收缓存和发送缓存区的大小。赋以的初值正是在TCP初始化时的遇到的sysctl_tcp_[w/r]mem数组。不知道为什么用的是每个数组的第2个值。这个值是允许用户去修改的。如果用心没有修改的话,默认的就是16KB和85KB。

感兴趣的可以去系统/proc/sys/net/ipv4/下看下,可以看到两个文件,每个文件只有一行,三列的数据。中间的数值就是上面sk->sk_sndbuf和sk->sk_rcvbuf的值。

lin@linp:/proc/sys/net/ipv4$ ls tcp_[wr]mem
tcp_rmem  tcp_wmem
lin@linp:/proc/sys/net/ipv4$ cat tcp_rmem;cat tcp_wmem
4096    87380   6108448
4096    16384   4194304


1890 atomic_inc(&tcp_sockets_allocated);

最后一个语句。增加了一个变量的值。从变量的名称就能看出,这个是记录系统分配了多少个TCP socket。

tcp_v4_init_sock返回

tcp_v4_init_sock函数执行完毕了。函数依次返回到inet_create,__sock_create,sock_create, sys_socket中。

返回后,下面还有一个重要的函数要提,就是sock_map_fd。因为这个函数会把生成的struct socket *sock映射为一个文件ID,就是int类型的变量。让用户通过这个ID来调用socket。为什么要这样做呢?这是unix系统里的宗旨,“一切皆文件”,向用户提供一致的易用的接口。

1211 retval = sock_map_fd(sock);

sock_map_fd(sock);

同样定义在net/socket.c中。

394 int sock_map_fd(struct socket *sock)
395 {
396     struct file *newfile;
397     int fd = sock_alloc_fd(&newfile);
399     if (likely(fd >= 0)) {
400         int err = sock_attach_fd(sock, newfile);
402         if (unlikely(err < 0)) {
403             put_filp(newfile);
404             put_unused_fd(fd);
405             return err;
406         }
407         fd_install(fd, newfile);
408     }
409     return fd;
410 }


396 struct file *newfile;

396 定义了一个文件指针变量。这里的file仍然是内核里面的数据类型。

397 int fd = sock_alloc_fd(&newfile);

把指针的地址传入sock_alloc_fd,为其分配一个file类型的变量。并返回一个没有使用的文件ID。这个函数不负责ID和file变量之间的关联。

400 int err = sock_attach_fd(sock, newfile);

把sock和新分配的文件指针关联起来。sock_attach_fd同样是在net/socket.c中定义。关联的步骤为:

1. 370 从socket超级块中分配一个目录entry。

2. 374-381 按照socket文件系统要求初始化这个entry。

3. 383 把sock的文件指针指向要关联的文件,完成关联。

4. 384-389 初始化文件一些属性。把file的private_data(类型为void*)指向sock。对应的文件操作函数集合为socket_file_ops。

365 static int sock_attach_fd(struct socket *sock, struct file *file)
366 {
367     struct dentry *dentry;
368     struct qstr name = { .name = "" };
370     dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
371     if (unlikely(!dentry))
372         return -ENOMEM;
374     dentry->d_op = &sockfs_dentry_operations;
380     dentry->d_flags &= ~DCACHE_UNHASHED;
381     d_instantiate(dentry, SOCK_INODE(sock));
383     sock->file = file;
384     init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
385           &socket_file_ops);
386     SOCK_INODE(sock)->i_fop = &socket_file_ops;
387     file->f_flags = O_RDWR;
388     file->f_pos = 0;
389     file->private_data = sock;
391     return 0;
392 }


回到sock_map_fd中。

407 fd_install(fd, newfile);

前面文件的关联都没有问题了。这时可以把文件ID fd和新生成的文件指针 newfile指向的文件关联起来了。具体的关系过程涉及到进程的文件管理,比较复杂。不多说了。

此时,sys_socket也执行完成了。socket创建也就完成了,返回的ID值就是以后用来引用socket的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp-ip socket创建