写在前面: 计划写一个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
最近实验室的学弟们貌似对缓冲区很感兴趣,听到很多次在讨论缓冲区。今天也来写篇文章和大家讨论一下。从I/O,到缓冲区都会谈到。首先是所有语言都提供了执行I/O的较高级别的工具,例如ANSI C提供了标准I/O库,C++重载了<<和>>等,这些不依赖于系统内核,所以移植性强,而且这个缓冲区的分配长度和优化等细节都是代你处理好了。在Unix系统中,是通过使用有内核提供的系统级Unix I/O函数来实现这些较高级别的I/O函数的。 高级别I/O函数工作很好,上面也提到了几点优点,为什么还要学习Unix I/O呢? 了解Unix I/O可以帮你理解其他的系统概念。比如进程、存储器层次结构、链接和加载等。 有时候除了使用Unix I/O 以外别无选择。有些重要情况下,使用高级I/O函数不能实现想要的功能,比如标准I/O库没有提供读取文件元数据的方式,比如文件大小或文件创建时间等。 I/O 概念: 输入/输出(I/O)是在主存和外部设备(如磁盘驱动器、终端和网络)之间拷贝数据的过程 继续阅读 >>


杜肖孟 17/11/16 19:52:35
多线程多进程关闭连接的区别 首先来看看close和shutdown两个系统调用对应的内核函数: #define __NR_close 3 __SYSCALL(__NR_close, sys_close) #define __NR_shutdown 48 __SYSCALL(__NR_shutdown, sys_shutdown) 上图是调用close和shutdown关闭连接时的函数调用过程,sys_close和sys_shutdown这两个系统调用最终是由tcp_close和tcp_shutdown方法来实现的。 由此我们可以来看一个问题:当socket被多进程或者多线程共享时,关闭连接时有何区别? 从图中可以看到 sys_close封装调用过程中有一个fput函数,它有它有一个引用计数,记录这个socket被引用了多少次。当这个引用计数不为0时,是不会触发真正 继续阅读 >>


杜肖孟 17/11/02 11:47:30
我们知道当服务器绑定、监听了指定端口后,内核通常会为每一个LISTEN状态的socket维护两个队列: SYN队列(半连接队列):由/proc/sys/net/ipv4/tcp_max_syn_backlog指定,表示处于 SYN_RECV 状态的队列 ACCEPT队列(全连接队列):由listen()函数的第二个参数 backlog 指定,内核硬限制由 net.core.somaxconn 限制,即实际的值由min(backlog,somaxconn) 来决定。表示已完成连接的队列,等待被 accept系统调用取走。 TCP三次握手如何与accept交互呢? 看下面这张图: 客户端使用connect向服务器发送TCP连接,三次握手就发生了。当1.1步骤 客户端首先发送SYN到达服务端后,内核会把连接信息放到SYN队列中,同时回一个SYN+ACK包给客户端。一段时间后,客户端再次发来ACK包后,内核会把连接从SYN队列中取出,再把这个连接放到ACCEPT队列中。服务器调用accept 继续阅读 >>


杜肖孟 17/10/28 14:03:12
TCP提供一种面向连接的、可靠的基于流的服务。 面向连接:在彼此交换数据之前必须先建立一个TCP连接,双方互相确认,仅有两方彼此通信。 可靠:数据被分割成TCP认为最适合发送的数据块;TCP发出一个段后启动一个定时器,超时重传;TCP收到另一端的数据后,将回复一个确认;TCP将保持它首部和数据的校验和,以检测数据在传输过程中的任何变化;必要时TCP将对收到的数据进行重新排序;TCP还能提供流量控制。 基于流的服务:应用程序对数据的发送和接受是没有边界限制的,发送段指定的写操作和接受段执行的读操作的次数之间没有任何的数量关系。 提供全双工通信。数据在两个方向上独立的进行传输,连接的每一端必须保持每个方向上的输出数据序号。 TCP首部 通常是20个字节。 发送端和目的端的端口号:用于标识发端和收端的应用进程。一个IP地址和一个端口号称为一个socket,插口对(包含源端IP、源端口、目的IP、目的端口)可唯一确定一个TCP连接。 32位序号:用来标识从TCP发端向TCP收端发送的数 继续阅读 >>


杜肖孟 17/10/19 23:51:39
三种模型 计算机网络是物理计算机连接起来成的系统,以及工作于系统上的协议。 网络协议分层方式常见有三种,一种是OSI七层模型,一种是TCP/IP四层模型,一种是五层模型。 五层模型的数据封装 物理层:比特传输 把电脑通过电缆、光缆连接起来,主要规定了网络的一些电气特性,负责传送0和1的电信号。 数据链路层:相邻网络元素(主机、交换机、路由器等)的数据传输 电脑连接起来后,就可以传送高低电位了,但是单纯的0和1没有任何意义,必须规定解读方式:多少个电信号算一组?每个信号位有什么意义? 以太网协议 规定一组电信号构成一个数据包,叫做“帧”,每一帧分为两部分:标头(Head)和数据(Data)。 “标头”包含数据包的一些说明项,比如发送者(源物理地址)、接收者、数据类型、CRC校验码等。“数据”则是数据包的具体内容。具体的帧结构如下所示: “标头”的长度固定为18个字节(6+6+2+4=18),“数据”的长度,最短为46字节,最长为1500字节(MTU,最大传输单 继续阅读 >>


杜肖孟 17/10/19 23:11:52
什么是计算机网络? 主机之间通过交换网络互连,交换节点一般是路由器或者交换机。 什么是网络协议? 为进行网络中的数据交换而建立的规则、标准或约定。 协议的三要素是什么? 语法、语义、时序 计算机网络的结构? 网络边缘:主机(端系统)、网络应用 主机(端系统):运行网络应用程序 客户/服务器(C/S)应用模型:客户发送请求,接受服务器响应 对等(P2P)应用模型:不仅依赖专用服务器;对等实体之间直接进行通信 接入网络,物理介质:有线或无线通信链路,将网络边缘接入核心网络 带宽(bps):网络中指数据传输速率,Mb/s 共享/独占? 无线接入网络: 无线局域网(LANs):wifi 广域无线接入:通过电信运营商,3G、4G 网络核心:互联的路由器(或分组转发设备),将数据从源主机通过网络核心发送到目的主机 关键功能:路由+转发 路由:确定分组从源到目的传输路径 路由算法 转发:将分组从路由器的输入端口交换至正确的输出端口 本地转发表 继续阅读 >>


杜肖孟 17/10/19 20:56:07
Redis网络模型是一个使用IO多路复用、单线程、非阻塞的模型。这个模型的优点在于单线程不用考虑加锁,如果在单核环境上可以将效率发挥到最大。它没有那么庞大,代码一共2000多行,因此比较容易分析,学长推荐。 另外@浅墨学长拿出了redis网络部分的代码,设计了应用层协议,添加了应用层buffer,定义了服务器类型,完成了一个基于Redis网络模型的简易网络库,我fork了一份,然后跟着学长的博客 Redis网络库源码分析 以及网上搜集的资料,把这部分的源码根据自己的理解分析了一下,添加了很多注释,扔到我的git上,大概了解了服务端的工作过程,分享出来以供大家参考与我后期的回顾。 附上链接:Redis网络库源码浅解 参考资料: 什么是 Event Loop? 杨博东的博客 作者:Tanswer_ 发表于2017/8/12 16:43:52 原文链接 阅读:152 评论:0 查看评论 继续阅读 >>


杜肖孟 17/08/12 16:43:52
线程池介绍 服务器完成一项任务的时间可分为:T1:创建线程或进程时间;T2:执行任务时间;T3:销毁进程或线程时间。通常T1+T3的时间大于T2,线程池正是关注如何缩短T1和T3的时间。 线程池通过在系统中预先创建一定数量的线程,当任务请求到来时从线程池中分一个预先创建的线程去处理任务,线程在处理完任务后还可以重用,不会销毁,继续等待下次任务的到开。这样能避免大量的线程创建和销毁操作,从而节省系统资源;同时有很多任务时,也会减少创建线程的数量。 用C++11的线程相关特性,比如线程、条件变量、互斥量,让我们编写并发程序更简单。 半同步半异步线程池实现的关键技术分析 线程池又三层组成: 1. 同步服务层:不断的将新任务添加到同步队列中,可以用多路复用或者多线程来完成。一开始没看懂任务是什么,其实一个函数就是一个任务,C++11通过std::function将函数封装为类模板对象,可以将这些任务(函数)放到容器中保存起来,以进行添加读取任务操作。 2. 排队层:就是一个同步队列,处于核心地位。所有待处理的任务都存在这里,要保证队列中共享数据线程安全 继续阅读 >>


杜肖孟 17/08/11 16:03:45
左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字。 比如 int a = b + c;,a 就是一个左值,可以对a取地址,而b+c 就是一个右值,对表达式b+c 取地址会报错。C++11中右值又由两个概念组成:将亡值和纯右值。 纯右值和将亡值 在C++98中,右值是纯右值,纯右值指的是临时变量值、不跟对象关联的字面量值。包括非引用的函数返回值、表达式等,比如 2、‘ch’、int func()等。将亡值是C++11新增的、与右值引用相关的表达式。 纯右值:非引用返回的临时变量( int func(void) )、运算表达式产生的临时变量(b+c)、原始字面量(2)、lambda表达式等。 将亡值:将要被移动的对象、T&&函数返回值、std::move返回值和转换为T&&的类型的转换函数的返回值。 将亡值可以理解为通过“盗取”其他变量内存空间的方式获取到的值。在确保其他变量不再被使用、或即将被销毁时,通过“盗取”的方 继续阅读 >>


杜肖孟 17/08/09 21:37:30