Linux网络协议栈(一)——Socket入门(2)

简介:

3、套接字的实现
套接字最先是在UNIX的BSD版本实现的,所以也叫做BSD套接字,它隐藏了各个协议之间的差异,并向上提供统一的接口。Linux中实现套接字的基本结构:

3.1、BSD套接字
3.1.1、核心数据结构
为了实现BSD套接字,内核提供一个重要的数据结构struct socket,它的定义如下:

复制代码
复制代码
 //BSD套接字(include/linux/net.h)
struct socket {
    socket_state        state;  //套接字状态
    unsigned long        flags;
    struct proto_ops    *ops; //操作函数集
    struct fasync_struct    *fasync_list;
    struct file        *file;//每个BSD套接字都有一个inode结点,通过文件对象与其关联起来  
    struct sock        *sk; //socket内部结构,与具体的协议簇(比如PF_INET)相关
    wait_queue_head_t    wait;
    short            type;    //套接字类型:如SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, and SOCK_PACKET
    unsigned char        passcred; 
};

//BSD套接字操作函数集
struct proto_ops {
    int        family;
    struct module    *owner;
    int        (*release)   (struct socket *sock);
    int        (*bind)         (struct socket *sock,
                      struct sockaddr *myaddr,
                      int sockaddr_len);
    int        (*connect)   (struct socket *sock,
                      struct sockaddr *vaddr,
                      int sockaddr_len, int flags);
    int        (*socketpair)(struct socket *sock1,
                      struct socket *sock2);
    int        (*accept)    (struct socket *sock,
                      struct socket *newsock, int flags);
    int        (*getname)   (struct socket *sock,
                      struct sockaddr *addr,
                      int *sockaddr_len, int peer);
    unsigned int    (*poll)         (struct file *file, struct socket *sock,
                      struct poll_table_struct *wait);
    int        (*ioctl)     (struct socket *sock, unsigned int cmd,
                      unsigned long arg);
    int        (*listen)    (struct socket *sock, int len);
    int        (*shutdown)  (struct socket *sock, int flags);
    int        (*setsockopt)(struct socket *sock, int level,
                      int optname, char __user *optval, int optlen);
    int        (*getsockopt)(struct socket *sock, int level,
                      int optname, char __user *optval, int __user *optlen);
    int        (*sendmsg)   (struct kiocb *iocb, struct socket *sock,
                      struct msghdr *m, size_t total_len);
    int        (*recvmsg)   (struct kiocb *iocb, struct socket *sock,
                      struct msghdr *m, size_t total_len,
                      int flags);
    int        (*mmap)         (struct file *file, struct socket *sock,
                      struct vm_area_struct * vma);
    ssize_t        (*sendpage)  (struct socket *sock, struct page *page,
                      int offset, size_t size, int flags);
};
//BSD套接字状态
typedef enum {
    SS_FREE = 0,            /* not allocated        */
    SS_UNCONNECTED,            /* unconnected to any socket    */
    SS_CONNECTING,            /* in process of connecting    */
    SS_CONNECTED,            /* connected to socket        */
    SS_DISCONNECTING        /* in process of disconnecting    */
} socket_state; 
复制代码
复制代码

3.1.2、BSD套接字初始化

复制代码
复制代码
//net/socket.c
//BSD套接字的初始化
void __init sock_init(void)
{
    int i;

    /*
     *    Initialize all address (protocol) families. 
     */
     
    for (i = 0; i < NPROTO; i++) 
        net_families[i] = NULL; //协议簇数组初始化

    /*
     *    Initialize sock SLAB cache.
     */
     //分配sock缓存
    sk_init();

#ifdef SLAB_SKB
    /*
     *    Initialize skbuff SLAB cache 
     */
    skb_init();
#endif

    /*
     *    Initialize the protocols module. 
     */

    init_inodecache();

    //注册sockfs文件系统
    register_filesystem(&sock_fs_type);
    //安装sockfs
    sock_mnt = kern_mount(&sock_fs_type);
    /* The real protocol initialization is performed when
     *  do_initcalls is run.  
     */

#ifdef CONFIG_NETFILTER
    netfilter_init();
#endif
}


//net/socket.c
//sockfs文件系统的安装点
static struct vfsmount *sock_mnt;
//sockfs文件系统类型
static struct file_system_type sock_fs_type = {
    .name =        "sockfs",
    .get_sb =    sockfs_get_sb,
    .kill_sb =    kill_anon_super,
}; 
//地址簇及协议信息
static struct net_proto_family *net_families[NPROTO]; 
复制代码
复制代码

sock_init在系统初始化的被调用:

3.1.3、BSD套接字的系统调用
实际上,Linux内核只提供了一个与套接字相关的系统调用,即sys_socketcall,应用程序的所有套接字调用都会映射到这个系统调用上。

复制代码
复制代码
//BSD套接字调用入口(net/socket.c)
asmlinkage long sys_socketcall(int call, unsigned long __user *args)
{
    unsigned long a[6];
    unsigned long a0,a1;
    int err;

    if(call<1||call>SYS_RECVMSG)
        return -EINVAL;

    /* copy_from_user should be SMP safe. */
    if (copy_from_user(a, args, nargs[call]))//从用户区拷贝参数
        return -EFAULT;
        
    a0=a[0];
    a1=a[1];
    
    switch(call)  //调用相应的函数
    {
        case SYS_SOCKET:
            err = sys_socket(a0,a1,a[2]);
            break;
        case SYS_BIND:
            err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
            break;
        case SYS_CONNECT:
            err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
            break;
        case SYS_LISTEN:
            err = sys_listen(a0,a1);
            break;
        case SYS_ACCEPT:
            err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
            break;
        case SYS_GETSOCKNAME:
            err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
            break;
        case SYS_GETPEERNAME:
            err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
            break;
        case SYS_SOCKETPAIR:
            err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);
            break;
        case SYS_SEND:
            err = sys_send(a0, (void __user *)a1, a[2], a[3]);
            break;
        case SYS_SENDTO:
            err = sys_sendto(a0,(void __user *)a1, a[2], a[3],
                     (struct sockaddr __user *)a[4], a[5]);
            break;
        case SYS_RECV:
            err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
            break;
        case SYS_RECVFROM:
            err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
                       (struct sockaddr __user *)a[4], (int __user *)a[5]);
            break;
        case SYS_SHUTDOWN:
            err = sys_shutdown(a0,a1);
            break;
        case SYS_SETSOCKOPT:
            err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
            break;
        case SYS_GETSOCKOPT:
            err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);
            break;
        case SYS_SENDMSG:
            err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);
            break;
        case SYS_RECVMSG:
            err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);
            break;
        default:
            err = -EINVAL;
            break;
    }
    return err;
}

//include/asm/unistd.h
#define __NR_socketcall        102  //系统调用号
复制代码
复制代码

下面来看一下sys_socket的实现:

Code

3.2、INET套接字
INET套接字就是支持 Internet 地址族的套接字,它位于TCP协议之上, BSD套接字之下,如下:

3.2.1、数据结构

Code

inet_init()函数:

Code

sock_register()函数:

Code

inet_create()函数

Code

 

 
 
目录
相关文章
|
1月前
|
安全 Linux 网络安全
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
67 0
Nipper 3.9.0 for Windows & Linux - 网络设备漏洞评估
|
2月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
162 18
|
2月前
|
网络协议 关系型数据库 Linux
【App Service Linux】在Linux App Service中安装 tcpdump 并抓取网络包
在App Service for Linux环境中,无法像Windows一样直接使用网络排查工具抓包。本文介绍了如何通过TCPDUMP在Linux环境下抓取网络包,包括SSH进入容器、安装tcpdump、执行抓包命令及下载分析文件的完整操作步骤。
163 6
|
3月前
|
Web App开发 网络协议 Linux
【Linux】网络基础
TCP/IP五层模型是网络通信的基础框架,将复杂的数据传输过程分为物理层、数据链路层、网络层、传输层和应用层,每层各司其职,协同完成远程通信。该模型确保了不同设备和网络之间的互联互通,是现代互联网运行的核心机制。
233 5
|
3月前
|
网络协议 Linux 开发者
深入Linux中UDP网络通信机制编程探索
以上步骤概述了Linux中UDP网络通信的编程机制。在实现时,因关注细节和上下文环境可能有所调整,但大致流程是一致的。这些知识片段旨在帮助开发者快速上手Linux下的UDP编程,并提供可靠的信息作为编程的基础。在编程实践中,应结合实际业务需求,设计合适的数据传输协议,确保数据的正确性和实时性。
83 0
|
10月前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
239 17
|
10月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
196 10
|
10月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
10月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
210 10
|
10月前
|
监控 安全 网络安全
网络安全与信息安全:漏洞、加密与意识的交织
在数字时代的浪潮中,网络安全与信息安全成为维护数据完整性、保密性和可用性的关键。本文深入探讨了网络安全中的漏洞概念、加密技术的应用以及提升安全意识的重要性。通过实际案例分析,揭示了网络攻击的常见模式和防御策略,强调了教育和技术并重的安全理念。旨在为读者提供一套全面的网络安全知识框架,从而在日益复杂的网络环境中保护个人和组织的资产安全。