Linux网络连接内核

Linux网络连接内核

1. 连接是一个数据结构

连接的本质是内核中的一种数据结构(即结构体)。Linux 系统内核,会用 C 语言设计多态结构,其中套接字编程就是如此设计的。

我们使用的 socket() 函数,在内核中有一个 struct socket 结构体管理连接的基本信息,其中 short type 字段,就是决定创建的是UDP还是TCP的。而 struct sock *sk 就是网络 socket 的接口,它所指向的就是UDP或TCP的结构体。

c 复制代码
struct socket {
    socket_state          state;     /* 当前 socket 的状态 */
    short                 type;      /* socket 类型(SOCK_STREAM, SOCK_DGRAM 等) */
    unsigned long         flags;     /* socket 标志 */
    struct file           *file;     /* 与 socket 相关的文件描述符 */
    struct sock           *sk;       /* 指向内核中的 sock 结构体 */
    const struct proto_ops *ops;     /* socket 操作集合 */
};

在UDP和TCP的结构体中,它们都是由多种套接字结构体嵌套组成的,这种俄罗斯套娃式的结构体,就是c语言风格的多态结构。

以TCP为例,TCP的结构体是 struct tcp_sock,它的最上边是 struct sockstruct sock又在 struct inet_sock 之中,struct inet_sock 又在 struct inet_connection_sock 之中。C 语言使用多态的方式,是使用一个指针类型,想要访问 TCP 里的 struct sock 就把指针强转成 struct *sock 类型,访问 struct inet_sock 就把指针强转成 struct *inet_sock 类型,以此类推。

struct sock:

c 复制代码
struct sock {
    /* 同步控制相关 */
    spinlock_t            sk_lock;            /* 用于保护此 sock 的自旋锁 */
    atomic_t              sk_refcnt;          /* 引用计数 */

    /* 协议层状态 */
    struct sock_common    __sk_common;
    struct proto         *sk_prot;            /* 指向协议相关的函数操作 */
    void                 *sk_user_data;       /* 用户数据 */
    
    /* 发送和接收缓冲区 */
    struct sk_buff_head    sk_receive_queue;   /* 接收队列 */
    struct sk_buff_head    sk_write_queue;     /* 发送队列 */

    /* 协议相关的状态变量 */
    unsigned long          sk_flags;           /* socket 标志 */
    unsigned int           sk_rcvbuf;          /* 接收缓冲区大小 */
    unsigned int           sk_sndbuf;          /* 发送缓冲区大小 */
    
    /* ... 还有很多其他字段 */
};

struct tcp_sock:

c 复制代码
struct tcp_sock {
    struct inet_sock       inet;             /* IPv4 socket */
    u32                    rcv_nxt;          /* 下一个要接收的序列号 */
    u32                    snd_nxt;          /* 下一个要发送的序列号 */
    u32                    snd_una;          /* 已确认的第一个字节 */
    u32                    snd_wnd;          /* 发送窗口 */
    u32                    rcv_wnd;          /* 接收窗口 */

    u32                    srtt;             /* 平滑的往返时间 */
    u32                    mdev;             /* 往返时间的均方差 */
    
    u32                    retransmit_high;  /* 重传的最高序列号 */
    
    /* 拥塞控制相关 */
    u32                    snd_cwnd;         /* 拥塞窗口 */
    u32                    snd_ssthresh;     /* 慢启动阈值 */

    /* ... 其他和 TCP 协议相关的字段 */
};

struct udp_sock:

c 复制代码
struct udp_sock {
    struct inet_sock       inet;            /* IPv4 协议相关的 socket */

    __u16                  len;             /* UDP 数据长度 */
    __u16                  pending;         /* 未决的数据包状态 */

    /* 用于UDP-Lite传输的校验和,普通UDP协议不使用 */
    __u8                   encap_type;      /* 封装类型 */
    __u8                   encap_enabled;   /* 是否启用了封装 */
    __u8                   no_check6_tx;    /* 不校验传出数据 */
    __u8                   no_check6_rx;    /* 不校验传入数据 */

    int                    (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
    int                    (*encap_err_rcv)(struct sock *sk, struct sk_buff *skb,
                                            struct iphdr *iph, u32 info);

    /* UDP-Lite特有的字段(在标准 UDP 协议下不使用) */
    __u16                  pcslen;          /* 部分校验和长度 */
    __u16                  pcflag;          /* 部分校验标志 */

    /* ... 其他字段 */
};

2. 一切皆文件与套接字

Linux 具有一切皆文件的特点,在套接字编程中,Linux 能够将 sockfd 当成普通的文件描述符使用、关闭,但在 Windows 环境下,必须为 sockfd 额外写一个关闭文件描述符的函数。那么,Linux 是如何做到将连接当成文件看待的呢?

根据文件操作,进程的PCB结构体 task_struct 中有一个 *file 指针,指向 struct file_struct 结构体,这个结构体中,有一个 struct file *fd_array[] 记录着所有打开的文件描述符 fd ,它的元素指向对应打开的文件,也是由一个 struct file 结构体管理的,其中的 void *private_data 在套接字编程中,就是指向 struct socket 套接字结构体,这一串的联系,使得套接字能够像文件一样被管理,也是 Linux 具有一切皆文件的特点的原因。

相关推荐
2302_79952574几秒前
【Hadoop】Hadoop集群安装中出现的问题
linux·hadoop
MoloXuanhe6 分钟前
[TryHackMe]Wordpress: CVE-2021-29447(wp漏洞利用-SSRF+WpGetShell)
运维·网络·安全·tryhackme·thm
刘一说6 分钟前
Linux调试命令速查:Java/微服务必备
java·linux·微服务
枫の准大一17 分钟前
【Linux游记】基础指令篇
linux
wanhengidc19 分钟前
网页版的云手机都有哪些优势?
运维·网络·安全·游戏·智能手机
ypf520828 分钟前
OrbStack 配置国内镜像加速
linux
Hello.Reader33 分钟前
一文通关 Proto3完整语法与工程实践
java·linux·数据库·proto3
Hello.Reader39 分钟前
一文吃透 Protobuf “Editions” 模式从概念、语法到迁移与实战
linux·服务器·网络·protobuf·editions
陌上花开缓缓归以1 小时前
linux ubi文件系统
linux
2418ly1 小时前
docker常用命令
运维·docker·容器