开发者角度 : int fd socket(AF_INET,SOCK_STREAM,0) 返回的是一个文件描述符用户态后续调用connect(fd, ...); send(fd, ...); recv(fd, ...); close(fd);本质上都是通过这个 fd 找到内核中的 socket 对象再进入协议栈。在源码中都做了哪些事/*用户态 socket(AF_INET, SOCK_STREAM, 0) - syscall 入口 - net/socket.c::SYSCALL_DEFINE3(socket) - net/socket.c::__sys_socket() - net/socket.c::__sys_socket_create() - net/socket.c::sock_create() - net/socket.c::__sock_create() - net/ipv4/af_inet.c::inet_create()*/socket_create是创建socket的主要位置它会调用__socket_create()函数int __sock_create(struct net *net, int family, int type, int protocol, struct socket **res, int kern){ /*net所属网络命名空间 family协议族比如 AF_INET typesocket 类型比如 SOCK_STREAM protocol协议号比如 0 表示让协议族自己选默认协议 res输出参数返回新建的 struct socket * kern是否是内核态创建的 socket。用户态路径传 0内核内部创建常传 1*/ - 检查 family/type 合法性 // 分配socket对象 socket sock_alloc() // 根据 family 找到对应协议族 pf rcu_deeference(net_families[family]); // 调用协议族的 create() 方法对于AF_INET对应的是 linux-6.6.143/net/ipv4/af_inet.c (inet_create) err pf-create(net, sock, protocol, kern); }对于inet_create函数来说它作用就是把一个“空的 struct socket”变成“已经绑定到 IPv4/TCP 的 socket 对象”。对 socket(AF_INET, SOCK_STREAM, 0) 来说它最终完成的是sock-ops inet_stream_opssock-sk-sk_prot tcp_protstatic int inet_create(struct net *net, struct socket *sock, int protocol, int kern){ /*在 AF_INET 的内部协议表里查找对应的 (type, protocol)*/ list_for_each_entry_rcu(answer, inetsw[sock-type], list) /* inetsw_array[] 的部分内容 {{ .type SOCK_STREAM, .protocol IPPROTO_TCP, .prot tcp_prot, .ops inet_stream_ops, .flags INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK, }}*/ // 让这个socket后续的 bind/listen/accept/sendmsg/recvmsg 都走 inet_stream_ops sock-ops answer-ops; // 获得tcp_prot answer_prot answer-prot; //创建真正的传输层对象 struct sock创建sock对象并把tcp_prot赋到sock-sk_prot sk sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern); // 把 struct socket 和 struct sock 绑定起来。实现上它会建立双向关联后面所有 socket 操作都能落到 sk。 sock_init_data(sock, sk); }void sock_init_data() 在这个函数中会把socke中的sk_data_ready函数指针进行初始化sk-sk_data_ready sock_def_readable;sk-sk_write_space sock_def_write_space;后续软中断收到数据包时会调用sk_data_ready函数指针来唤醒sock上等待的进程。bind 源码流程AI总结的fd- 找到对应的 struct socket- 把用户态 sockaddr 拷贝到内核态 address- 后续只操作内核里的这份地址- 调用 sock-ops-bind()- 进入协议族实现- 做协议/长度/权限检查- 进入 __inet_bind()- 检查地址是否合法- 分配/确认端口- 写入 socket 的本地地址和本地端口