Linux网络编程API函数初步剖析

今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作。

1、socket(family,type,protocol)

当我们在开发网络应用程序时,使用该系统调用来创建一个套接字。该API所做的工作如下所示:

该系统调用主要完成两个任务:“创建套接字”和“为套接字绑定文件句柄”。

socket{}结构定义如下:

 struct socket {

socket_state             state;  //socket状态

unsigned long           flags; //标识,如SOCK_ASYNC_NOSAPCE

const struct proto_ops  *ops; //协议特定的socket操作集

struct fasync_struct         *fasync_list; //异步唤醒队列

struct file                   *file; //指向文件的指针

struct sock                *sk; //指向下一层中的sock结构

wait_queue_head_t         wait; //等待在这个socket上的任务列表

short                           type; //数据包的类型

};

在创建socket套接字时,就是要完成ops、file和sk等这些成员的初始化。

1). 创建套接字:sock_create()

根据family参数值在全局数组struct net_proto_family net_families[]里找到我们所指定的地址簇。不同类型的地址簇都有一个struct net_proto_family{}类型的对象,例如我们常见的IPv4的inet_family_ops,IPv6的inet6_family_ops,X25协议的ax25_family_ops等。在内核是初始化时,这些模块会在自己的初始化函数内部调用sock_register()接口将各自的地址簇对象注册到net_families[]数组里。

我们分析的焦点集中在IPv4协议簇,即inet_family_ops对象上。重点是inet_create函数,该函数的主要任务就是创建一个socket套接字,并对其中相关结构体成员进行必要的初始化。至于它创建套接字时的依据和原理等到我们讲协议栈时大家就明白了,这里主要是让大家对其流程执行流程有个感性的把握。

sock_alloc()函数中我们创建一个struct socket{}类型的对象,假如叫做A,将socket()系统调用的第二参数type字段赋值给A->type。

在inet_create()函数中,我们根据type的值,在全局数组struct inet_protosw inetsw[]里找到我们对应的协议转换开关。而inetsw[]数组是在inet_init()函数里被初始化的:

其中inetsw_array[]是一个比较重要的数据结构,定义在af_inet.c文件中:

根据type的值,就可以确定struct socket{}->ops,到底是inet_stream_ops、inet_dgram_ops或者inet_sockraw_ops。然后,对应地,就以tcp_prot、udp_prot或raw_prot为输入参数,实例化一个struct sock{} 对象sk=sk_alloc()。紧接着建立socket{}和sock{}的关联,最后将socket()系统调用的第三个参数protocol付给sock{}对象中的属性sk_protocol。

看不懂别着急,我说过,这里只是给大家梳理整体流程,等到我们讲了协议栈章节,然后再回头看本篇,就感觉这些东西就太小儿科了。

2). 为套接字绑定文件句柄:sock_map_fd()

我们都知道网络套接字也是一种系统IO,所以不可避免的要与文件系统打交道。每个套接字都对应一个已打开的文件标识符,所以在套接字初始化完成后,就要将其和本地一个唯一的文件标识符关联起来,即建立socket{}和file{}之间的关联关系。

2、bind (sockfd, sockaddr, addrlen)

该系统调用在内核中的执行过程如下:

重点是socket->ops->bind()回调接口。我们现在已经知道了,针对IPv4而言,这里的ops无非就是inet_stream_opsinet_dgram_opsinet_sockraw_ops对象。碰巧的是,这三个对象中的bind函数指针均指向inet_bind()函数。只有原始套接字的情况,这里会去调用raw_prot对象的bind回调函数,即raw_bind()。

3、listen(sockfd, backlog)

这里我们可以看到面向无连接的套接字和原始套接字是不用listen的,只有流式套接字才有效。

4、connect(sockfd, sockaddr, addrlen)

从这幅图中我们确实看到,connect()系统调用不但可以面向连接的套接字,也可用于无连接及原始套接字。

5、accept(sockfd, sockaddr, addrlen)

同样地,我们看到只有面向连接的流式套接字调用accept()才有意义。最终调用的是tcp_prot对象的accept成员函数。

本篇主要进一步分析了网络编程中常见的几个API函数内部的调用流程,一方面可以使大家对这些API的有了更深的认识,不是仅仅停留在形而上的层面;另一方面为后面分析协议栈的实现原理,奠定坚实的基础。

未完,待续…

揭开网络编程常见API的面纱【上】的更多相关文章

  1. UNIX网络编程——揭开网络编程常见API的面纱【上】

    Linux网络编程API函数初步剖析 今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作. 1.socket(famil ...

  2. UNIX网络编程——揭开网络编程常见API的面纱【下】

    Linux网络编程数据收发的API流程分析        只要把数据在协议栈中的流动线路和脉络弄清楚了,关于协议栈的实现部分,理解起来就轻松多了.在网络编程章节的数据接收过程中,我们主要介绍过read ...

  3. Linux 高性能服务器编程——Linux网络编程基础API

    问题聚焦:     这节介绍的不仅是网络编程的几个API     更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系.     这节主要介绍三个方面的内容:套接字(so ...

  4. Linux网络编程基础API

    第5章 Linux网络编程基础API 探讨Linux网络编程基础API与内核中TCP/IP协议族之间的关系,并未后续章节提供编程基础.从3个方面讨论Linux网络API. socket地址API.so ...

  5. 服务器编程入门(4)Linux网络编程基础API

      问题聚焦:     这节介绍的不仅是网络编程的几个API     更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系.     这节主要介绍三个方面的内容:套接字( ...

  6. 转 Android网络编程之使用HttpClient批量上传文件 MultipartEntityBuilder

    请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件 http://www.tuicool.com/articles/Y7reYb 我曾在<Andr ...

  7. iOS开发之网络编程--使用NSURLConnection实现文件上传

    前言:使用NSURLConnection实现文件上传有点繁琐.    本文并没有介绍使用第三方框架上传文件. 正文: 这里先提供用于编码测试的接口:http://120.25.226.186:3281 ...

  8. linux高性能服务器编程 (五) --Linux网络编程基础api

    第五章 Linux网络编程基础api 1.主机字节序和网络字节序 字节序是指整数在内存中保存的顺序.字节序分为大端字节序.小端字节序. 大端字节序:一个整数的高位字节数据存放在内存的低地址处.低位字节 ...

  9. 5 Linux网络编程基础API

    5.1   socket地址API 大端字节序(网络序):高位在低址,低位在高址 小端字节序(主机序):低位在低址,高位在高址 判断,利用联合的特性: #include <iostream> ...

随机推荐

  1. OSI七层模型详解(物理层、数据链路层、网络层、传输层.....应用层协议与硬件)

    原文链接 https://blog.csdn.net/xw20084898/article/details/39438783

  2. CF294C Shaass and Lights(排列组合)

    题目描述 There are n n n lights aligned in a row. These lights are numbered 1 1 1 to n n n from left to ...

  3. [tree]合并果子(哈夫曼树+优先队列)

    现在有n堆果子,第i堆有ai个果子.现在要把这些果子合并成一堆,每次合并的代价是两堆果子的总果子数.求合并所有果子的最小代价. Input 第一行包含一个整数T(T<=50),表示数据组数. 每 ...

  4. 构建高可靠hadoop集群之0-hadoop用户向导

    本文翻译自:http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-hdfs/HdfsUserGuide.html 基于2.8. ...

  5. Windows登录密码明文获取器

    软件原理:本软件根据开源工具mimikatz2.0 修改!软件能直接读取系统明文密码! 支持32位.64位系统 win xp/vista/7/8/8.1 本机win10专业版测试不能获取,虚拟机win ...

  6. jquery把数组中年月相同的数组重新组成新的数组

    //原数组var data = { results: [{ id:0, date:'2017-12-12', content:'123' },{ id:0, date:'2017-12-12', co ...

  7. Python核心框架tornado的异步协程的2种方式

    什么是异步? 含义 :双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位 现象:没有共同的时钟,不考虑顺序来了 ...

  8. 构建ExtJS 6.x程序

    构建ExtJS 6.x程序 ExtJS也有自己的打包工具 SenchaCmd,它用来生成构建ExtJS前端组织架构,最后打包发布生产,操控着前端整个开发生命周期,SenchaCmd依赖于JDK,所以要 ...

  9. Learning Experience of Big Data: Connect CentOs to Xshell and set Java environment on CentOS

    1.set up connections between vitural machine and Xshell: After we connect the virtural machine to ne ...

  10. [转]Makefile中使用$$的使用

    在makefile中,会经常使用shell命令,也经常见到$var 和 $$var的情况,有什么区别呢,区别大了.不要认为在makefile的规则的命令行中使用$var就是将makefile的变量和s ...