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 具有一切皆文件的特点的原因。

相关推荐
zhougl99623 分钟前
html处理Base文件流
linux·前端·html
泥土编程1 小时前
kubekey -实现懒人一键部署K8S集群
linux·运维
yuzhangfeng2 小时前
【云计算物理网络】从传统网络到SDN:云计算的网络演进之路
网络·云计算
TDengine (老段)2 小时前
TDengine 中的关联查询
大数据·javascript·网络·物联网·时序数据库·tdengine·iotdb
zhu12893035563 小时前
网络安全的现状与防护措施
网络·安全·web安全
Aa美少女战士3 小时前
单域名 vs 通配符:如何选择最适合你的 SSL 证书?
网络协议·https·ssl
咕噜签名3 小时前
如何申请p12证书
网络协议·https·ssl
2a3b4c3 小时前
SSL/TLS
网络协议·https·ssl
wirepuller_king4 小时前
创建Linux虚拟环境并远程连接,finalshell自定义壁纸
linux·运维·服务器
zhu12893035565 小时前
网络安全与防护策略
网络·安全·web安全