主要涉及到的类和实现文件有: Endian.h 提供了字节序转换的函数。 Socket.h/Socket.cc socketfd 的封装,提供了绑定地址、开始listen、接受连接等操作,并可设置套接字选项。 InetAddress.h/InetAddress.cc 套接字地址的封装,提供了多种方式初始化一个地址,还提供方法从地址中拿到 ip 和 port。 SocketsOps.h/SocketsOps.cc 封装了 socket 相关的一些操作,提供给 Socket 和 InetAddress 用。 这部分就是基本的 TCP 套接字编程和套接字选项的知识,代码逻辑也很简单,推荐看下 UNP卷一 的相关章节。 下面逐一看下这几个相关的文件。 字节序转换部分(Endian.h) #ifndef MUDUO_NET_ENDIAN_H #define MUDUO_NET_ENDIAN_H #include <stdint.h> #include <endian.h 继续阅读 >>


杜肖孟 18/01/09 15:14:11
eventfd 介绍 Linux 2.6.27后添加了一个新的特性,就是eventfd,是用来实现多进程或多线程的之间的事件通知的。 接口 #include <sys/eventfd.h> int eventfd(unsigned int initval, int flags); 这个函数会创建一个事件对象(eventfd object),返回一个文件描述符,用来实现进程或线程间的等待/通知(wait/notify)机制。内核为这个对象维护了一个无符号的64位整形计数器 counter,用第一个参数(initval)初始化这个计数器,创建时一般可将其设为0,后面有例子测试这个参数产生的效果。 flags 可以使用三个宏: EFD_CLOEXEC:给这个新的文件描述符设置 FD_CLOEXEC 标志,即 close-on-exec,这样在调用 exec 后会自动关闭文件描述符。因为通常执行另一个程序后,会用全新的程序替换子进程的正文,数据,堆和栈等,原来的文件描述符变量也不存 继续阅读 >>


杜肖孟 18/01/08 23:22:55
muduo 的定时器功能由三个 class 实现,TimerId、Timer 和 TimerQueue。 TimerId 类 它唯一标识一个 Timer 定时器。TimerId Class 同时保存Timer* 和 sequence_,这个 sequence_ 是每个 Timer 对象有一个全局递增的序列号 int64_t sequence_,用原子计数器(AtomicInt64)生成。 它主要用于注销定时器,这样就可以区分地址相同的先后两个 Timer 对象。 namespace muduo { namespace net { class Timer; /// /// An opaque identifier, for canceling Timer. /// /* 带有唯一标识的Timer,主要用于取消Timer */ class TimerId : public muduo::copyable { public: TimerId() : timer_(NULL), 继续阅读 >>


杜肖孟 18/01/07 15:41:05
本文分析一下Reactor模式的实现,关键是三个类:Channel、Poller、EventLoop。 事件分发类 Channel Channel 是 selectable IO channel,负责注册与响应IO事件,包括注册给Poller的 fd 及其监听的事件,以及事件发生了所调的回调函数。 每个Channel对象自始至终只负责一个 fd 的事件分发,封装了一系列该 fd 对应的操作,使用了回调函数,包括可读、可写、关闭和错误处理四个。 首先给定Channel所属的 loop,及其要处理的 fd;接着注册 fd 上需要监听的事件,如果是常用的读写事件的话,可以直接调用接口函数enableReading或enableWriting来注册对应fd上的事件,disable*是销毁指定的事件;然后通过 set*Callback 来设置事件发生时的回调。 注册事件时函数调用关系,如下:Channel::update()->EventLoop::updateChannel(Channel* 继续阅读 >>


杜肖孟 18/01/06 18:36:02
考虑让我的 web server 增加对 PHP 的支持,这就要用到 php 解析器来将客户端请求的 php 文件解析为静态资源,再由我的 web server 将其返回到客户端,php-fpm 就可以来帮我们完成这个工作。可是我的 web server 如何与 php-fpm 通信呢? 接下来就是本文的主角:FastCGI 。 FastCGI 实现与测试代码:https://github.com/Tanswer/FastCGI Web Server 项目地址:https://github.com/Tanswer/Xserver Description C language through FastCGI protocol, through php-fpm, php file parsed into html files. How to use Preparation: please make sure you have installed php-fpm. Testing enviro 继续阅读 >>


杜肖孟 17/12/23 14:46:54
32 位的平台上,线性地址空间为固定的 4GB,并且由于采用了保护机制,Linux内核将这 4GB 分为两部分,线性地址较高的 1GB(0xC0000000 到 0xFFFFFFFF )为共享的内核空间;而较低的 3GB 为每个进程的用户空间。由于每个进程都不能直接访问内核空间,而是通过系统调用间接进入内核,因此所有的进程都共享内核空间。而每个进程都拥有各自的用户空间,各个进程之间不能互相访问彼此的用户空间。 一个进程的用户地址空间主要由两个数据结构来描述。一个是 mm_struct 结构,它对进程的整个用户空间进行描述,简称内存描述符;另一个是 vm_area_struct 结构,它对用户空间中各个区间( 代码区、数据区等 )进行描述。 进程用户空间的描述 内存描述符 每个进程只有一个 mm_struct 结构,在每个进程的 task_struct 结构中,有一个指向该结构的指针。 struct mm_struct { struct vm_area_struct *m 继续阅读 >>


杜肖孟 17/12/10 14:47:55
链接器之所以存在或者产生,基本上是由于程序开发的模块化。这里讲的模块,主要是编译概念上的模块,通常他们按照功能划分,比如一个.c或者.cpp文件就是一个编译单元,就是一个模块,编译后就产生一个.o目标文件。为了最终生成一个可执行文件、静态库或者动态库,就需要把各个编译单元按照特定的约定组合到一起。这里特定的约定指的就是“目标文件格式”,它定义了目标文件、库文件和可执行文件的格式,这里组合这一过程就叫做链接。 链接主要有以下几个任务:空间与地址分配,符号解析,重定位,昨天晚上回宿舍躺床上后,一直在想这几个过程,哪个先进行,哪个后进行,试图从目标文件开始理清链接进行的顺序,知直到生成可执行文件。但是我失败了,索性不管了,我大概清楚这几个过程都做了什么工作就好,如果纠结的失眠了第二天就起不来了=_=。用到的样例代码 在文末。 空间与地址分配 主流操作系统中,可执行文件都是基于虚拟地址空间的,即每个可执行文件都有相同且独立的地址空间,并且文件中各个段(代码段,数据段,以及进程空间中的堆栈段)都有相似的布局 继续阅读 >>


杜肖孟 17/12/06 15:38:25
编译器编译源代码后生成的文件叫做目标文件,从结构上讲它是已经编译后的可执行文件格式,只是还没有经过链接,其中可能有些符号或有些地址还没有调整。它本身就是按照可执行文件格式存储的,跟真正的可执行文件在结构上稍有不同。 目标文件的格式: 现在 PC 平台流行的可执行文件格式主要是 Windows 下的 PE( Portable Executable,可移植可执行 ) 和 Linux 的 ELF( Executable and Linkable Format,可执行链接格式 ),它们都是 COFF (Common Object Fifle Format,一般目标文件格式 )格式的变种。从广义上看,目标文件和可执行文件的格式其实几乎是一样的,在 Linux 下,我们可以将他们统称为 ELF 文件;在 Windows 下可以统称为 PE-COFF 文件格式。 在 Linux 下使用 file 命令查看相应的文件格式: 目标文件是什么样的 目标文件是什么样的呢? 下面我们通过一个具体的例子 继续阅读 >>


杜肖孟 17/12/04 20:58:14
写在前面: 分页机制完成线性地址到物理地址的转换 80x86 规定分页机制是可选的。分段和分页没有什么必然联系,分段可以说是 Intel 的 CPU 一直保持着的一种机制,而分页只是保护模式下的一种内存管理策略。想开启分页机制,CPU必须工作在保护模式,而工作在保护模式可以不开启分页。 分页机制由控制寄存器 CR0 中的 PG 位启用,如PG=1则启用分页机制,把线性地址转换为物理地址;如果PG=0则直接把段机制产生的线性地址当作物理地址使用。 为什么要分页? 问题的本质是在目前只分段的情况, CPU 认为线性地址等于物理地址,而线性地址是由编译器编译出来的,它本身是连续的,所以物理地址也必须要连续才行,但我们可用的物理地址不连续。换句话说,如果线性地址连续,而物理地址可以不连续,不就解决了吗。所以要解除线性地址和物理地址一一对应的关系,然后将他们的关系重新建立,通过某种映射关系,可以将线性地址映射到任意物理地址。 页与页表 为了效率起见,将线性地址空间分成若干大小相等的片,称为页( 继续阅读 >>


杜肖孟 17/12/02 14:51:54
写在前面: 计划写一个Web 服务器,在小组的群博上没有找到相关的文章,自己打算从开始记录下这个过程,一是整理清楚我的构建过程,二是也能让后面的同学做一下参考。 CSAPP上网络编程那一章最后实现了一个小但是功能较齐全的Web 服务器,叫做TINY。因为只是知道HTTP协议的一些概念,还不太清楚一个Web服务器的工作流程和代码组织结构,而书上给出了 Tiny Server 的完整实现,代码非常短,只有几百行,所以自己模仿着手撸了一遍,并试着分析了代码,运行了一下,给自己一个直观的认识。源代码放在 这里,加注释的代码放在这里。接下来分析下这个Tiny Web服务器。 PS:WEB基础就不写了,自己了解下基本的概念,那么看起代码来就足够了。 CSAPP上面的例子用到的一些通用的函数都放在csapp.h头文件中,并在csapp.c中给出实现。我们看到的大写首字母开头的函数,是在原功能函数上面加上了错误处理,比如 pid_t Fork(void) { pid_t pid; 继续阅读 >>


杜肖孟 17/11/19 21:23:24