揭开网络编程常见API的面纱【上】
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_ops、inet_dgram_ops或inet_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的面纱【上】的更多相关文章
- UNIX网络编程——揭开网络编程常见API的面纱【上】
Linux网络编程API函数初步剖析 今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作. 1.socket(famil ...
- UNIX网络编程——揭开网络编程常见API的面纱【下】
Linux网络编程数据收发的API流程分析 只要把数据在协议栈中的流动线路和脉络弄清楚了,关于协议栈的实现部分,理解起来就轻松多了.在网络编程章节的数据接收过程中,我们主要介绍过read ...
- Linux 高性能服务器编程——Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字(so ...
- Linux网络编程基础API
第5章 Linux网络编程基础API 探讨Linux网络编程基础API与内核中TCP/IP协议族之间的关系,并未后续章节提供编程基础.从3个方面讨论Linux网络API. socket地址API.so ...
- 服务器编程入门(4)Linux网络编程基础API
问题聚焦: 这节介绍的不仅是网络编程的几个API 更重要的是,探讨了Linux网络编程基础API与内核中TCP/IP协议族之间的关系. 这节主要介绍三个方面的内容:套接字( ...
- 转 Android网络编程之使用HttpClient批量上传文件 MultipartEntityBuilder
请尊重他人的劳动成果,转载请注明出处:Android网络编程之使用HttpClient批量上传文件 http://www.tuicool.com/articles/Y7reYb 我曾在<Andr ...
- iOS开发之网络编程--使用NSURLConnection实现文件上传
前言:使用NSURLConnection实现文件上传有点繁琐. 本文并没有介绍使用第三方框架上传文件. 正文: 这里先提供用于编码测试的接口:http://120.25.226.186:3281 ...
- linux高性能服务器编程 (五) --Linux网络编程基础api
第五章 Linux网络编程基础api 1.主机字节序和网络字节序 字节序是指整数在内存中保存的顺序.字节序分为大端字节序.小端字节序. 大端字节序:一个整数的高位字节数据存放在内存的低地址处.低位字节 ...
- 5 Linux网络编程基础API
5.1 socket地址API 大端字节序(网络序):高位在低址,低位在高址 小端字节序(主机序):低位在低址,高位在高址 判断,利用联合的特性: #include <iostream> ...
随机推荐
- oracle行长度大小和页行数修改
行长度展示长度: /*查询长度*/ SQL> show linesize; /*查询行长度大小*/linesize 100SQL> set linesize200; /*修改行长 ...
- zTree的核心处理逻辑
zTree 是一个前端树形结构的插件. 使用起来很简单,我们重点关注一下插件的核心代码. 首先,zTree需要如下的数据结构: let areaData = [ { "id": & ...
- 关于Vue-cli 跨域,即使是非自己的服务器也可以get到内容
刚入门vue ,打算用vue的脚手架做一个小项目.需要用到第三方的api,无奈遇到各种各样的问题. 比如 Access-Control-Allow-Origin ,或者使用了ajax的jsonp模式之 ...
- atan和atan2反正切计算
typedef struct point { double x, y; }point; //给定两个点 point a(x1,y1),b(x2,y2); 使用反三角函数atan求斜率,原型如下 flo ...
- 洛谷P3871 [TJOI2010]中位数(splay)
题目描述 给定一个由N个元素组成的整数序列,现在有两种操作: 1 add a 在该序列的最后添加一个整数a,组成长度为N + 1的整数序列 2 mid 输出当前序列的中位数 中位数是指将一个序列按照从 ...
- MySQL必会
SQL语言对大小写不敏感,但一般使用大.1.创建数据库 CREATE DATABASE test; 2.授予权限 CRANT ALL ON test.* to user(s); 3.使用指定数据库 U ...
- 软件的按契约设计(DbC---Design by Contract)
一.DbC基本概念 DbC的思想源于商业活动中商家和用户的行为(义务和利益关系),双方都要遵守一个契约(合同),交易才能完成. 商家与用户的契约关系如下: 1. 商家必须提供某种产品(义务),并有权获 ...
- python爬虫之有道在线翻译
今天初学了python这门课 老师简单的讲解了一下 python的安装环境,配置环境变量,当前主流Python使用的是3.x版本, 下午简单的讲解了python的起源,发展以及在各个方面的应用 然后晚 ...
- 动态规划(DP)算法
参考https://blog.csdn.net/libosbo/article/details/80038549 动态规划是求解决策过程最优化的数学方法.利用各个阶段之间的关系,逐个求解,最终求得全局 ...
- x86的控制寄存器CR0,CR1,CR2,CR3
状态和控制寄存器组除了EFLAGS.EIP ,还有四个32位的控制寄存器,它们是CR0,CR1,CR2和CR3. 这几个寄存器中保存全局性和任务无关的机器状态. CR0中包含了6个预定义标志,0位是保 ...