socket函数的domain、type、protocol解析

2023-05-16


socket函数的domaintypeprotocol解析


                                                                                                                                  lxg@2015-04-09


  1. 内核中的socket概览

    图一:socket概览


内核中套接字是一层一层进行抽象展示的,把共性的东西抽取出来,这样对外提供的接口可以尽量的统一。内核中把套接字的定义会抽象出来展示,如struct sock->struct inet_sock->struct tcp_sock从抽象到具体。还会把套接字的操作也会抽象,下面我们会提到怎么进行抽象展示的。


Socket函数中的三个参数其实就是把抽象的socket具体化的条件,domain参数决定了图中所示的第二层通信域,type决定了第三层的通信模式,protocol决定了第四层真正的通信协议。


  1. Domain参数


Domain参数指定了通信的”(在后文中会用family替代domain),我们是在IPv4还是IPv6这个范围内通信,也就决定了我们通信的地址是IPv4格式还是IPv6格式。通常可选的定义如下:


名称

目的

AF_UNIX, AF_LOCAL

本地通信

AF_INET

IPv4网络通信

AF_INET6

IPv6网络通信

AF_PACKET

链路层通信


Linux系统中AF_*PF_*是等价的。


在内核源码中net目录下面有Af_开头的一系列文件(:Af_inet.cAf_inet6.cAf_unix.c),每一个文件分别代表了一种协议族。


Net.h中定义了一个结构体:


//net_proto_family结构体定义了每一个协议族的新建socket句柄

struct net_proto_family {

    int     family;

    int     (*create)(struct net *net, struct socket *sock,

                  int protocol, int kern);

    struct module   *owner;

};

//Af_inet.c中的PF_INET domain的定义

static const struct net_proto_family inet_family_ops = {

    .family = PF_INET,

    .create = inet_create,

    .owner  = THIS_MODULE,

};


         在协议栈初始化的通过sock_register(const struct net_proto_family *ops)(socket.c)函数把协议栈支持的协议族family加入net_families数组中。


         当我们通过socket系统调用创建套接字的时候流程走到__sock_create函数(SYSCALL_DEFINE3->sock_create->__sock_create)的时候根据familynet_families数组中取得对应协议族的create句柄,所以对于PF_INET协议族的套接字就是调用inet_create来新建socket


         通过上面分析可知family这个参数决定了调用哪个协议族create函数来新建socket,说得可能不准确点就是决定了你使用net/目录下面的哪个Af_*.c文件中的函数。


  1. Type参数


Type就是socket的类型,对于AF_INET协议族而言有流套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)


/**

 * enum sock_type - Socket types

 * @SOCK_STREAM: stream (connection) socket

 * @SOCK_DGRAM: datagram (conn.less) socket

 * @SOCK_RAW: raw socket

 * @SOCK_RDM: reliably-delivered message

 * @SOCK_SEQPACKET: sequential packet socket

 * @SOCK_DCCP: Datagram Congestion Control Protocol socket

 * @SOCK_PACKET: linux specific way of getting packets at the dev level.

 *        For writing rarp and other similar things on the user level.

*/

enum sock_type {

    SOCK_STREAM = 1,

    SOCK_DGRAM  = 2,

    SOCK_RAW    = 3,

    SOCK_RDM    = 4,

    SOCK_SEQPACKET  = 5,

    SOCK_DCCP   = 6,

    SOCK_PACKET = 10,

};


在内核协议栈中有一个很重要的结构体,定义了每一个协议族中套接字在传输层的操作集合。PS:这里我理解传输层包括了套接字类型(STREAM,DGRAM)和具体的传输层协议(TCP,UDP)


/* This is used to register socket interfaces for IP protocols.  */

struct inet_protosw {

    struct list_head list;

 

        /* These two fields form the lookup key.  */

    unsigned short   type;     /* This is the 2nd argument to socket(2). */

    unsigned short   protocol; /* This is the L4 protocol number.  */

 

    struct proto     *prot;

    const struct proto_ops *ops;

 

    unsigned char    flags;      /* See INET_PROTOSW_* below.  */

};


struct proto_ops结构体定义了每一种套接字类型 (SOCK_STREAMSOCK_DGRAMSOCK_RAW)的操作集合,在Af_inet.c中分别定义了inet_stream_opsinet_dgram_opsinet_sockraw_ops这三种类型的proto_ops


const struct proto_ops inet_stream_ops = {

    .family        = PF_INET,

    .owner         = THIS_MODULE,

    .release       = inet_release,

    .bind          = inet_bind,

    .connect       = inet_stream_connect,

    .socketpair    = sock_no_socketpair,

    .accept        = inet_accept,

    .getname       = inet_getname,

    .poll          = tcp_poll,

    .ioctl         = inet_ioctl,

    .listen        = inet_listen,

    .shutdown      = inet_shutdown,

    .setsockopt    = sock_common_setsockopt,

    .getsockopt    = sock_common_getsockopt,

    .sendmsg       = inet_sendmsg,

    .recvmsg       = inet_recvmsg,

    .mmap          = sock_no_mmap,

    .sendpage      = inet_sendpage,

    .splice_read       = tcp_splice_read,

#ifdef CONFIG_COMPAT

    .compat_setsockopt = compat_sock_common_setsockopt,

    .compat_getsockopt = compat_sock_common_getsockopt,

    .compat_ioctl      = inet_compat_ioctl,

#endif

};


我们新建socket的时候指定了typeSOCK_STREAM那么在后面的套接字操作中(connect)会调用对应的inet_stream_ops中对应的函数(inet_stream_connect)



2inetswinet_protoswproto_opsproto的关系图


  1. Protocol参数


上文中我们通过familytype已经基本确定了新建的socket具体是什么类型的套接字,最后一步通过protocol来确定socket到底支持的哪个协议(TCP?UDP?)


inet_protosw结构体中我们已经解释过proto_ops对应的是每一种套接字类型的操作集合,那么可知struct proto对应的就是具体协议的操作集合。在Tcp_ipv4.c中定义TCP协议的struct proto tcp_prot


struct proto tcp_prot = {

    .name           = "TCP",

    .owner          = THIS_MODULE,

    .close          = tcp_close,

    .connect        = tcp_v4_connect,

    .disconnect     = tcp_disconnect,

    .accept         = inet_csk_accept,

    .ioctl          = tcp_ioctl,

    .init           = tcp_v4_init_sock,

    .destroy        = tcp_v4_destroy_sock,

    .shutdown       = tcp_shutdown,

    .setsockopt     = tcp_setsockopt,

    .getsockopt     = tcp_getsockopt,

    .recvmsg        = tcp_recvmsg,

    .sendmsg        = tcp_sendmsg,

    .sendpage       = tcp_sendpage,

    .backlog_rcv        = tcp_v4_do_rcv,

    .release_cb     = tcp_release_cb,

    .hash           = inet_hash,

    .unhash         = inet_unhash,

    .get_port       = inet_csk_get_port,

    .enter_memory_pressure  = tcp_enter_memory_pressure,

    .stream_memory_free = tcp_stream_memory_free,

    .sockets_allocated  = &tcp_sockets_allocated,

    .orphan_count       = &tcp_orphan_count,

    .memory_allocated   = &tcp_memory_allocated,

    .memory_pressure    = &tcp_memory_pressure,

    .sysctl_mem     = sysctl_tcp_mem,

    .sysctl_wmem        = sysctl_tcp_wmem,

    .sysctl_rmem        = sysctl_tcp_rmem,

    .max_header     = MAX_TCP_HEADER,

    .obj_size       = sizeof(struct tcp_sock),

    .slab_flags     = SLAB_DESTROY_BY_RCU,

    .twsk_prot      = &tcp_timewait_sock_ops,

    .rsk_prot       = &tcp_request_sock_ops,

    .h.hashinfo     = &tcp_hashinfo,

    .no_autobind        = true,

#ifdef CONFIG_COMPAT

    .compat_setsockopt  = compat_tcp_setsockopt,

    .compat_getsockopt  = compat_tcp_getsockopt,

#endif

#ifdef CONFIG_MEMCG_KMEM

    .init_cgroup        = tcp_init_cgroup,

    .destroy_cgroup     = tcp_destroy_cgroup,

    .proto_cgroup       = tcp_proto_cgroup,

#endif

};


所以对于TCP socket当执行connect连接的时候经过的流程大致是SYSCALL_DEFINE3 connect(系统调用)->inet_stream_connect(inet_stream_ops中定义)-> tcp_v4_connect(tcp_prot中定义)


  1. Family&type&protocol结合


上面分别说明了familytypeprotocol这三个参数代表的意义,接下来我们把这三个参数结合起来一起看一下最后的效果。


struct inet_protosw结构体在内核中是如何初始化的呢?


/* Upon startup we insert all the elements in inetsw_array[] into

 * the linked list inetsw.

 */

static struct inet_protosw inetsw_array[] =

{

    {

        .type =       SOCK_STREAM,

        .protocol =   IPPROTO_TCP,

        .prot =       &tcp_prot,

        .ops =        &inet_stream_ops,

        .flags =      INET_PROTOSW_PERMANENT |

                  INET_PROTOSW_ICSK,

    },

 

    {

        .type =       SOCK_DGRAM,

        .protocol =   IPPROTO_UDP,

        .prot =       &udp_prot,

        .ops =        &inet_dgram_ops,

        .flags =      INET_PROTOSW_PERMANENT,

       },

 

       {

        .type =       SOCK_DGRAM,

        .protocol =   IPPROTO_ICMP,

        .prot =       &ping_prot,

        .ops =        &inet_dgram_ops,

        .flags =      INET_PROTOSW_REUSE,

       },

 

       {

           .type =       SOCK_RAW,

           .protocol =   IPPROTO_IP,    /* wild card */

           .prot =       &raw_prot,

           .ops =        &inet_sockraw_ops,

           .flags =      INET_PROTOSW_REUSE,

       }

};


Af_inet.c中定义了PF_INET协议族的四个初始化的inet_protosw结构体,在内核协议栈初始化的时候通过inet_register_protosw函数将这些结构体按照类型(type)hash到全局的inetsw数组中。


 


3socket调用流程


上面是socket系统调用的一个主要的流程图,左半部分在前文中已经提到过了。当流程走到inet_create函数的时候根据typeinetsw数组中找到对应类型套接字的inet_protosw结构体,我们前面提到协议栈中已经定义了PF_INET协议族支持的inet_protosw结构体,总共有4个。


找到inet_protosw结构体以后还需要进一步判断protocolinet_protosw中定义的protocol是否是一致的。内核中定义支持的protocol有一个特殊的值IPPROTO_IP(IPPROTO_IP0),可以理解为一个通配符也可以理解为一个默认值,就是说我不指定protocol,由内核自己决定使用哪一个protocol


那么内核根据什么来选择protocol?就是根据内核定义的全局inetsw中对应类型的inet_protosw中的protocol


说起来可能比较拗口,直接看一下代码就很清楚了。


    list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {

 

        err = 0;

        /* Check the non-wild match. */

        if (protocol == answer->protocol) {

            if (protocol != IPPROTO_IP)

                break;

        } else {

            /* Check for the two wild cases. */

            if (IPPROTO_IP == protocol) {

                protocol = answer->protocol;

                break;

            }

            if (IPPROTO_IP == answer->protocol)

                break;

        }

        err = -EPROTONOSUPPORT;

    }


所以如果我们在新建套接字的时候使用socket(PF_INET,SOCK_STREAM,0),那么内核就会默认给你把protocol修正为IPPROTO_TCP


好吧,其实整篇文章我就是想搞清楚这最后的一句话。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socket函数的domain、type、protocol解析 的相关文章

  • Libevent3——bufferevent上创建socket通信的服务器端、客户端的流程、及服务器端、客户端的代码实现分析⛽

    承接上文 服务器监听流程简要如下 创建监听器 有客户端连上时就是满足条件的时候 监听器的回调函数被调用 回调函数会创建新的用于通信的文件描述符fd 那么fd是需要被封装到一个bufferevent对象中 所以再创建一个bev对象对fd进行封
  • iOS平台Socket编程实践(一)

    iOS平台Socket编程实践 关于TCP Socket编程基础可以参看我的 我所不知道的TCP Socket编程 系列文章 iOS平台Socket编程主要内容及辅助工具 1 TCP协议编程 2 UDP协议编程 3 WireShark抓包辅
  • QTcpSocket 发送数据心得

    遇到不会用的函数前 最好还是看看手册QAQ 今天居然吃了这个大亏 先交代一下背景 在做TCP客户端的发送数据功能 要和服务器程序进行TCP IP通信 且根据通信协议要发送数组或者结构体 并且数组的每一个位都是有效数据位 因此不能像大多数人一
  • ‘windows socket error:由于目标机器积极拒绝,无法连接。(10061),on API 'connect'的错误?

    1 gt 连接时出现 windows socket error 10061 on API connect 是SOCKET没有启动 SCKTSRVR EXE 或者无法连接到服务器 端口等 使用socketconnect很简单 只要在应用服务器
  • unity游戏开发-socket网络通信

    本篇主要是分享基于unity的客户端socket网络通信方案 关于服务器的c socekt搭建放在了这里 基于C 的Tcp服务端通信 其中关于socekt粘包断包的处理放在这里分享了 C socket粘包断包处理 目录 整体设计 TcpCl
  • Socket -- udp

    接收者 完成System out println UDPProvider Started 作为接收者 指定一个端口用于数据接收 DatagramSocket ds new DatagramSocket 20000 构建接收实体 final
  • c# 使用udp协议接收消息

    两个例子 例一 引用命名空间 using System Net using System Net Sockets 定义 private UdpClient Reveive IPAddress localIP IPAddress Parse
  • 计算机网络-----网络编程

    网络编程 实战 网络基础 1 什么是计算机网络 2 什么是网络编程 3 网络编程中的主要问题 4 网络通信要素 5 通信协议分层思想 IP和端口号 1 IP 1 1定义 1 2IP的分类 2 端口号 2 1定义 2 2端口号的分类 网络通信
  • Java实战项目(一)---编写聊天室程序

    刚开始学java 参考 java从入门到精通 这本书 学到网络程序设计基础这一章节 尤其与其他计算机进行通信 觉得还挺有意思的 所有深入地试试做一个小程序 聊天室程序 在代码中加入我自己的理解和困惑 希望能和大家一起探讨 每行的代码基本都有
  • Unity使用C#实现简单Scoket连接及服务端与客户端通讯

    简介 网络编程是个很有意思的事情 偶然翻出来很久之前刚开始看Socket的时候写的一个实例 贴出来吧 Unity中实现简单的Socket连接 c 中提供了丰富的API 直接上代码 服务端代码 Thread connectThread 当前服
  • websocket详解

    之前利用websocket以及jQuery做了一个聊天通讯应用 最近在总结整个过程中的一些问题 也借此机会聊聊websocket协议 webSocket本身不存在跨域问题 所以可以利用webSocket来进行非同源之间的通信 webSock
  • /etc/init.d/mysql: No such file or directory 和 ERROR 2002 (HY000): Can't connect to local MySQL server through socket 解决办法

    更改 etc my cnf client password your password port 3306 socket tmp mysql sock Here follows entries for some specific progr
  • 推荐七种开源免费的C/C++网络库

    1 ACE 庞大 复杂 适合大型项目 开源 免费 不依赖第三方库 支持跨平台 2 Asio Asio基于Boost开发的异步IO库 封装了Socket 简化基于socket程序的开发 开源 免费 支持跨平台 3 POCO POCO C Li
  • C# 网络编程之Tcp实现客户端和服务器聊天

    最近使用Socket网络套接字编程中 在同步与异步通讯中客户端与服务器总是无法响应 但在学习Tcp协议编程中完成了通讯聊天功能 下面简单讲讲我最近学到的及Tcp聊天的源代码及详细注释 Tcp协议是一个传输层的协议 在Tcp协议编程中它通常使
  • C语言实现TCP连接

    开发环境 TCP服务端 TCP UDP测试工具 开发环境 Linux 编程语言 C语言 TCP UDP测试工具工具的使用请自行百度 我们用这款软件模拟TCP服务端 效果展示 代码编写 include
  • Go_一文入门网络编程:常见协议、通信过程、Socket、CS/BS、TCP/UDP

    网络编程三要素 ip地址 端口 协议 在网络通信协议下 不同计算机上运行的程序 可以进行数据传输 IP地址 IP地址是一种在互联网协议中用于识别和定位设备的32位或128位数字地址 它是一个设备在网络上的唯一标识符 用于在互联网上定位和识别
  • AF_INET和PF_INET的区别

    在写网络程序的时候 建立TCP socket一般是这样的 sock socket PF INET SOCK STREAM 0 然后在绑定本地地址或连接远程地址时需要初始化sockaddr in结构 其中指定address family时一般
  • socket连接超时问题

    一部分 把CSDN与中文yahoo翻了底朝天 也没找到如何设置socket的连接超时的满意方法 问此问题的兄弟已有一大堆 这里偶就讲一下win下如何设置socket的connect超时 设置connect的超时很简单 CSDN上也有人提到过
  • golang之跨语言ipc通信

    1 golang之跨语言ipc通信 文章目录 1 golang之跨语言ipc通信 1 1 unix domain Socket unix域套接字 介绍 1 2 IPC SOCKET通信 1 2 1 函数及地址定义介绍 1 2 2 UNIX
  • Socket编程中的强制关闭与优雅关闭及相关socket选项

    以下描述主要是针对windows平台下的TCP socket而言 首先需要区分一下关闭socket和关闭TCP连接的区别 关闭TCP连接是指TCP协议层的东西 就是两个TCP端之间交换了一些协议包 FIN RST等 具体的交换过程可以看TC

随机推荐

  • QT中为程序加入超级管理员权限

    QT的一些文件操作 xff0c 注册表的操作等 xff0c 有些操作会无效 xff0c 主要是因为没有对C盘的相关权限 解决方法 xff1a 1 mingw编译器 在pro工程文件中加入 span class hljs attribute
  • QT截图非顶层窗口的画面(获取窗口句柄)

    我们知道QT里截图的代码很简单 xff0c 很多例子都是截取桌面 xff0c 或截取整个屏幕 那如果要截取指定窗口的画面呢 xff1f 即使该窗口不在桌面最顶层显示 我们也能截到它的图片吗 xff1f 当然可以 xff0c 只要我们拿到该窗
  • QEventLoop会卡住的解决方法

    问题是这样的 xff1a 在一个线程中有下面一段代码 QEventLoop span class hljs keyword loop span span class hljs comment span span class hljs lab
  • android adb 模拟点击、滑动、输入、按键

    模拟输入 001 adb shell input text 001 模拟home按键 adb shell input keyevent 3 模拟点击 540 1104 坐标 adb shell input tap 540 1104 模拟滑动
  • 结构体在内存中的对齐规则

    一个结构体变量定义完之后 xff0c 其在内存中的存储并不等于其所包含元素的宽度之和 例一 xff1a include lt iostream gt using namespace std struct X char a
  • curl请求常用参数和返回码

    curl是一个用于传输数据的工具 xff0c 支持各种协议 xff0c 如HTTP FTP SMTP等 以下是一些常用的curl请求参数及其作用 xff1a X request xff1a 指定HTTP请求方法 xff0c 常见的有GET
  • ubuntu中python版本切换

    shell里执行 xff1a sudo update alternatives install usr bin python python usr bin python2 100 sudo update alternatives insta
  • CMAKE基础使用

    1 目录结构 xff1a 2 顶层cmake内容 xff1a span class token function cmake minimum required span span class token punctuation span V
  • URL格式

    一 URL基本格式 一个完整的url包含方案 用户名 密码 主机名 端口 路径 参数 查询和片段 xff0c 格式如下 xff1a lt scheme gt lt user gt lt password gt 64 lt host gt l
  • __IO uint16_t

    STM32里的类型定义 xff0c 见如下说明 xff1a typedef volatile unsigned short vu16 typedef IO uint16 t vu16 IO definitions access restri
  • 串口波形分析(TTL,RS232,RS485)

    TTL xff0c RS232 xff0c RS485波形分析 本文转自 xff1a http blog 163 com qiu zhi2008 blog static 60140977201092651854445 http www cn
  • Java数字类型转byte数组

    文章目录 方法1 自己写int转byte数组byte数组转int参考 xff1a https blog csdn net qq 41054313 article details 88424454 方法2 使用java NIO包的功能int转
  • 头文件和库函数的区别

    1 头文件中有函数的申明 xff0c 库文件实现函数的定义 比如 xff0c printf函数 使用时应包括stdio h xff0c 打开stdio h你只能看到 xff0c printf这 个函数的申明 却看不到printf具体是怎么实
  • C语言--字符串的截取

    今天碰到了一个字符串截取的功能实现问题 xff0c 比较常见所以就做下记录 一般的实现是这样的 xff1a include lt stdio h gt include lt string h gt int main void char de
  • 使用 JWT 让你的 RESTful API 更安全

    传统的 cookie session 机制可以保证的接口安全 xff0c 在没有通过认证的情况下会跳转至登入界面或者调用失败 在如今 RESTful 化的 API 接口下 xff0c cookie session 已经不能很好发挥其余热保护
  • CAN报文解析—案例

    1 CAN报文定义 CAN报文是指发送单元向接受单元传送数据的帧 我们通常所说的CAN报文是指在CAN线 xff08 内部CAN 整车CAN 充电CAN xff09 上利用ECU和CAN卡接收到的十六进制报文 2 CAN协议中CAN报文种类
  • 单片机中,intrins.h头文件中各函数详解:空指令_nop_(),移位函数_crol_、_cror_

    intrins h 在 C51单片机编程中 xff0c 我们经常使用到 nop 延时一个机器周期 如果晶振是12M xff0c 则延时1 us xff0c 该空函数在头文件intrins h中 头文件 INTRINS H 中的函数使用很方便
  • Linux 下模拟Http 的get or post请求(curl和wget两种方法)

    一 get请求 xff1a 1 使用curl命令 xff1a curl 34 http www baidu com 34 如果这里的URL指向的是一个文件或者一幅图都可以直接下载到本地 curl i 34 http www baidu co
  • QT入门基础认知(三个常用类、三种对话框类型、信号和槽)

    1 简单介绍 xff1a 1 1 三个常用类 xff08 Qwidget类 QDialog类 QMainwindow类 xff09 Qwidget类 xff1a 继承与QObject类和QPaintdevice类 xff0c 所有用户界面对
  • socket函数的domain、type、protocol解析

    socket 函数的 domain type protocol 解析 lxg 64 2015 04 09 内核中的 socket 概览 图一 xff1a socket 概览 内核中套接字是一层一层进行抽象展示的 xff0c 把共性的东西抽取