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

本文详细解析了Linux内核中UDP Socket的创建过程,包括sys_socket如何调用sock_create,sock_create内部如何通过__sock_create进行Socket的创建,并介绍了命名空间nsproxy的相关概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内核中的UDP socket流程(3)——sock_create
作者:gfree.wind@gmail.com

由于种种原因,工作的,私人的,学习停了几天。周末的时候,一天生病,还把《让子弹飞》和《非常勿扰2》看了。这两个片子还真火,几乎满座啊。非2远没有子弹好看,甚至还不如虎头蛇尾的《赵氏孤儿》呢。

好了,闲话少说。上次看到了sys_socket调用sock_create的地方了。下面开始研究sock_create了。

sys_socket将自己的参数family, type, protocol传给sock_create,而sock为sock_create的输出值。

retval = sock_create(family, type, protocol, &sock);


下面看sock_create的代码

int sock_create(int family, int type, int protocol, struct socket **res)
{
    return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}

sock_create不过是一个包装函数,它通过__sock_create真正的去创建socket。
其中,current是当前task的指针——实际上current是一个宏,这个宏在linux内核中已经存在很久了。task的类型为struct task_struct。nsproxy是它的一个成员变量,是task的命名空间指针,下面是它的定义:

struct nsproxy {
    atomic_t count;
    struct uts_namespace *uts_ns;
    struct ipc_namespace *ipc_ns;
    struct mnt_namespace *mnt_ns;
    struct pid_namespace *pid_ns;
    struct net      *net_ns;
};

与咱们有关的就是最后一个指针,net_ns。命名空间namespace是linux在2.6中引入的特性,是为了虚拟化而做的。具体定义可以参考 http://oldwiki.linux-vserver.org/Namespaces
uts_ns: UTS命名空间包含了运行内核的名称、版本、底层体系机构类型等信息。UTS是UNIX Timesharing System的缩写;
ipc_ns:保存所有与进程通信(IPC)有关的信息
mnt_ns:保存已mount的文件系统信息;
pid_ns:有关进程ID的信息;
net_ns:这是与咱们有关的,包含所有网络相关的命名空间。
这是第一个参数。
最后一个参数,则表明这个创建的socket是否为kernel层创建的。对于我们来说,这个socket是为应用层创建的,所有最后一个参数是0.

下面开始分析__sock_create

static int __sock_create(struct net *net, int family, int type, int protocol,
             struct socket **res, int kern)
{
    int err;
    struct socket *sock;
    const struct net_proto_family *pf;

    /*
     * Check protocol is in range
     */

    if (family 0 || family >= NPROTO)
        return -EAFNOSUPPORT;
    if (type 0 || type >= SOCK_MAX)
        return -EINVAL;

     /*
     * Skip some codes
     */

}

首先这个函数,先对family和type进行检查,查看是否超出正常范围。

唉,又12点了,明天再见了!

// 网络开发: UDP客户端 #include <stdio.h> #include <stdlib.h> #include <unistd.h> //延函数 #include <ohos_init.h> //系统初始化函数 #include <cmsis_os2.h> //内核开发函数 #include <string.h> //字符串处理函数 #include "wifi_device.h" #include "lwip/netifapi.h" #include "lwip/api_shell.h" #include "lwip/sockets.h" #include <netdb.h> #include "lwip/sockets.h" #include "wifi_connect.h" // 定义端口 #define _PROT_ 8888 // 在sock_fd 进行监听,在 new_fd 接收新的链接 int sock_fd; int addr_length; static const char *send_data = "Hello! I&#39;m BearPi-HM_Nano UDP Client!\n"; void UDP_Client_Thread(void *argument) { (void)argument; // 服务器地址信息 struct sockaddr_in send_addr; socklen_t addr_length = sizeof(send_addr); char recvBuf[512]; // 连接wifi WifiConnect("HUAWEI P60 Pro", "12345678"); // 创建socket if ((sock_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("create socket failed!\r\n"); exit(1); } // 初始化预连接的服务端地址 send_addr.sin_family = AF_INET; send_addr.sin_port = htons(_PROT_); send_addr.sin_addr.s_addr = inet_addr("192.168.43.38"); addr_length = sizeof(send_addr); // 总计发送 count 次数据 while (1) { bzero(recvBuf, sizeof(recvBuf)); // 发送数据到服务远端 sendto(sock_fd, send_data, strlen(send_data), 0, (struct sockaddr *)&send_addr, addr_length); // 线程休眠一段间 sleep(10); // 接收服务端返回的字符串 recvfrom(sock_fd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr *)&send_addr, &addr_length); printf("%s:%d=>%s\n", inet_ntoa(send_addr.sin_addr), ntohs(send_addr.sin_port), recvBuf); } // 关闭这个 socket closesocket(sock_fd); } void UDP_Client_Example(void) { osThreadAttr_t attr; attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = 1024 * 5; attr.priority = 25; attr.name = "UDP_Client_Thread"; if (osThreadNew(UDP_Client_Thread, NULL, &attr) == NULL) { printf("Failed to create UDP_Client_Thread!\n"); } } APP_FEATURE_INIT(UDP_Client_Example); 将其改成TCP客户端
最新发布
08-03
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值