内核中的UDP socket流程(4)——sock_create

简介: 内核中的UDP socket流程(4)——sock_create作者:gfree.wind@gmail.com原文:http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=85910又懒了2天,继续sock_create     /* Compatibility.
内核中的UDP socket流程(4)——sock_create
作者:gfree.wind@gmail.com

又懒了2天,继续sock_create

    /* Compatibility.

     This uglymoron is moved from INET layer to here to avoid
     deadlock in module load.
     */

    if (family == PF_INET && type == SOCK_PACKET) {
        static int warned;
        if (!warned) {
            warned = 1;
            printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
             current->comm);
        }
        family = PF_PACKET;
    }

    err = security_socket_create(family, type, protocol, kern);
    if (err)
        return err;

首先是对PF_INET,SOCK_PACKET的兼容性处理。 security_socket_create函数是一个空函数,省略。
下面是去申请一个socket node,我们需要进入sock_alloc中看如何分配的节点。

    /*
     *    Allocate the socket and allow the family to set things up. if
     *    the protocol is 0, the family is instructed to select an appropriate
     *    default.
     */

    sock = sock_alloc();
    if (!sock) {
        if (net_ratelimit())
            printk(KERN_WARNING "socket: no more sockets\n");
        return -ENFILE;    /* Not exactly a match, but its the
                 closest posix thing */

    }



下面是sock_alloc的代码

static struct socket *sock_alloc(void)
{
    struct inode *inode;
    struct socket *sock;

    inode = new_inode(sock_mnt->mnt_sb);
    if (!inode)
        return NULL;

    sock = SOCKET_I(inode);

    kmemcheck_annotate_bitfield(sock, type);
    inode->i_mode = S_IFSOCK | S_IRWXUGO;
    inode->i_uid = current_fsuid();
    inode->i_gid = current_fsgid();

    percpu_add(sockets_in_use, 1);
    return sock;
}

其中sock_mnt是一个全局变量,它在sock_init中被初始化的。并挂载到VFS层上。在sock_alloc函数中,首先是从sock_mnt->mnt_sb即socket的super block中申请一个节点。然后通过SOCKET_I宏,取得inode对应的socket的地址。
这里之所以这样做的,原因是因为,inode的分配是统一的,但是每个inode的用途是不一样的。
在socket中,申请的inode的节点,实际上对应的结构应该为下面这个结构。

struct socket_alloc {
    struct socket socket;
    struct inode vfs_inode;
};

new_inode中实际上是申请了一个struct socket_alloc的地址,但是返回的确是socket_all->vs_inode的地址。所以在这里需要使用SOCKET_I宏,来从inode地址中,得到socket的地址。

后面的宏kmemcheck_annotate_bitfield是一个内存检查,略过。然后,设置inode的mode,uid,gid。
percpu_add(sockets_in_use, 1)是增加sockets_in_use的统计计数——这个计数变量是每个cpu的私有变量。

然后,我们就回到__sock_create。

    rcu_read_lock();
    pf = rcu_dereference(net_families[family]);
    err = -EAFNOSUPPORT;
    if (!pf)
        goto out_release;

    /*
     * We will call the ->create function, that possibly is in a loadable
     * module, so we have to bump that loadable module refcnt first.
     */

    if (!try_module_get(pf->owner))
        goto out_release;

    /* Now protected by module ref count */
    rcu_read_unlock();

通过RCU机制,获得pf(family)对应的net_families中的指针。

下面通过调用函数指针调用用户指定family的函数去创建socket。

    err = pf->create(net, sock, protocol, kern);
    if (err 0)
        goto out_module_put;

对于TCP/IP来说,family是PF_INET。

现在又需要跳到文件linux/net/ipv4/af_inet.c,下面是PF_INET对应的协议域定义

static const struct net_proto_family inet_family_ops = {
    .family = PF_INET,
    .create = inet_create,
    .owner    = THIS_MODULE,
};

所以对于对于TCP/IP的socket来说,sock_create中这里的create函数实际上指向的是inet_create——这个函数明天再说,继续sock_create的代码。

    /*
     * Now to bump the refcnt of the [loadable] module that owns this
     * socket at sock_release time we decrement its refcnt.
     */

    if (!try_module_get(sock->ops->owner))
        goto out_module_busy;

    /*
     * Now that we're done with the ->create function, the [loadable]
     * module can have its refcnt decremented
     */

    module_put(pf->owner);
    err = security_socket_post_create(sock, family, type, protocol, kern);
    if (err)
        goto out_sock_release;
    *res = sock;

    return 0;

这几行代码的注释已经很清楚,到此sock_create已经完结。

目录
相关文章
|
8月前
|
存储 Python
Python网络编程基础(Socket编程) UDP 发送和接收数据
【4月更文挑战第10天】对于UDP客户端而言,发送数据是一个相对简单的过程。首先,你需要构建一个要发送的数据报,这通常是一个字节串(bytes)。然后,你可以调用socket对象的`sendto`方法,将数据报发送到指定的服务器地址和端口。
|
3月前
|
存储 网络协议 Java
【网络】UDP回显服务器和客户端的构造,以及连接流程
【网络】UDP回显服务器和客户端的构造,以及连接流程
66 2
|
3月前
|
网络协议 Linux 网络性能优化
Linux基础-socket详解、TCP/UDP
综上所述,Linux下的Socket编程是网络通信的重要组成部分,通过灵活运用TCP和UDP协议,开发者能够构建出满足不同需求的网络应用程序。掌握这些基础知识,是进行更复杂网络编程任务的基石。
193 1
|
8月前
|
网络协议 Java
Java的Socket编程:TCP/IP与UDP深入探索
Java的Socket编程:TCP/IP与UDP深入探索
119 0
|
4月前
|
C语言
C语言 网络编程(七)UDP通信创建流程
本文档详细介绍了使用 UDP 协议进行通信的过程,包括创建套接字、发送与接收消息等关键步骤。首先,通过 `socket()` 函数创建套接字,并设置相应的参数。接着,使用 `sendto()` 函数向指定地址发送数据。为了绑定地址,需要调用 `bind()` 函数。接收端则通过 `recvfrom()` 函数接收数据并获取发送方的地址信息。文档还提供了完整的代码示例,展示了如何实现 UDP 的发送端和服务端功能。
|
4月前
|
网络协议 Linux
TCP 和 UDP 的 Socket 调用
【9月更文挑战第6天】
|
8月前
|
算法 Linux 调度
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
505 1
xenomai内核解析--xenomai与普通linux进程之间通讯XDDP(一)--实时端socket创建流程
|
7月前
|
存储 网络协议 数据处理
【Socket】解决UDP丢包问题
UDP(用户数据报协议)是一种无连接的传输层协议,因其不保证数据包的顺序到达和不具备内置重传机制,导致在网络拥塞、接收缓冲区溢出或发送频率过快等情况下容易出现丢包现象。为应对这些问题,可以在应用层实现重传机制、使用前向纠错码等方法。这些方法在一定程度上可以缓解UDP通信中的丢包问题,提高数据传输的可靠性和效率。
|
6月前
|
Java 数据格式
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
110 0
|
7月前
|
网络协议 应用服务中间件 网络性能优化
解析TCP /UDP协议的 socket 调用的过程
【6月更文挑战第2天】该文介绍了传输层的两种主要协议TCP和UDP的区别。TCP是面向连接、可靠的,提供顺序无错的数据传输,而UDP则是无连接、不可靠的,不保证数据顺序或不丢失。