1.大端法与小端法

大端法:按照从最高有效字节到最低有效字节的顺序存储,称为大端法

小端法:按照从最低有效字节到最高有效字节的顺序存储,称为小端法

网际协议使用大端字节序来传送TCP分节中的多字节整数(比如16位端口号,32位IPv4地址)。

2.time_wait状态

客户端(执行主动关闭的那一端)连接在收到服务器的结束报文段(FIN, ACK),并没有直接进入CLOSED状态,而是转移到TIME_WAIT状态。在这个状态,客户端连接要等待一段长为2MSL(MSL: 报文段最大生存时间)的时间,才能完全关闭。

time_wait的存在原因:

01.可靠地实现TCP全双工连接的终止

假设最终的报文段(ACK)丢失了,服务器将重新发送(FIN,ACK), 因此客户端必须维护状态信息,以允许它重新发送最终那个ACK。要是客户不维护状态信息,它将响应以一个RST(另外一种类型的TCP分节), 该分节将被服务器解释为一个错误。

02.保证让迟来的TCP报文段有足够的时间被识别并丢弃,允许老的重复分节在网络中消逝

TIME_WAIT状态的持续时间是MSL的2倍,这就足以让某个方向的分组最多存活MSL秒被丢弃,另一个方向上的应答最多存活MSL秒被丢弃,即确保网络上两个传输方向上尚未被接收到的、迟到的TCP报文段都已经消失(被中转路由器丢弃)。

time_wait的危害:

如果是服务器主动关闭连接后异常终止,则因为它总是使用同一个知名服务端口号,所以连接的TIME_WAIT状态将会导致服务器程序退出后不能立即重启

如何避免time_wait状态:

可以通过打开SO_REUSEADDR套接字选项来强制进程立即使用处于TIME_WAIT状态的连接占用的端口,即使以前建立的将该端口用作它们的本地端口的连接仍存在。

3. select/poll/epoll/kqueue对比

3.1 select .vs. poll:

01.实现细节上的区别:

select()和poll()都使用了相同的内核poll例程集合,这些poll例程有别于系统调用poll()集合本身。每个例程都返回有关单个文件描述符就绪的信息。这个就绪信息以位掩码的形式返回,其值同poll()系统调用中返回的revents字段中的比特值相关。

poll()系统调用的实现:为每个文件描述符调用内核poll例程,并将结果信息填到对应的revents字段中去

select()系统调用的实现:内核使用一组宏将内核poll例程返回的信息转化为由select()返回的与之对应的事件类型

02.API之间的区别:

select()能同时检测的文件描述符数量有上限限制(FD_SETSIZE,linux下值为1024),而poll()在理论上无此限制。

由于select()的参数fd_set同时也是保存调用结果的地方,如果要在循环中重复调用select()的话,我们必须每次都要重新初始化fd_set。而poll()因为是通过独立的两个字段events(针对输入)和revents(针对输出)来处理,从而避免每次都要重新初始化参数。

select()提供的超时精度(微秒)比poll()提供的超时精度(毫秒)高。

如果其中一个被检查的文件描述符被关闭了,通过在对应的revents字段中设定POLLNVAL标记,poll()会准确告诉我们是哪一个文件描述符被关闭了。与之相反,select()只会返回-1,并设置错误码为EBADF。

3.2 epoll .vs. select & poll

01. select & poll在监视大量的文件描述符时,性能远差于epoll。

原因: select & poll采用的都是轮询的方式,每次调用都要扫描并返回整个注册文件描述符集合,因此其检测就绪事件的算法复杂度为O(N)。epoll则在内核中维护一个事件表,epoll_wait()每次调用,都直接从该内核事件表中取得用户注册的事件,而无需反复地从用户空间读入这些事件。epoll_wait()采用回调的方式,内核检测到就绪的文件描述符时,将触发回调函数,回调函数就将该文件描述符上对应的事件插入内核就绪事件队列,内核将在适当的时机将该就绪队列中的内容拷贝到用户空间。因此epoll_wait无需轮询整个文件描述符集合来检测哪些事件已经就绪,其算法复杂度为O(1)。

02. select & poll只能工作在相对低效的LT模式,而epoll则可以工作在ET高效模式。并且epoll还支持EPOLLONESHOT事件,该事件能进一步减少可读、可写和异常等事件被触发的次数。

03. select内部是数组实现,poll内部是链表实现,所以select有最大fd限制,二者均有用户态到内核态的拷贝过程,两者的切换和数据拷贝都很消耗性能;而epoll内部是一棵红黑树,且因为epoll采取了共享内存机制,从而避免了用户态和内核态之间的切换。

3.2 kqueue .vs. epoll 

性能上:epoll每次只能更新一个兴趣列表中的文件描述符状态,换句话说,如果要在兴趣列表中更新100个文件描述符状态,就需要调用100次epoll_ctl()函数。大量的系统调用会显著地降低性能;但是,你可以通过多次使用EV_SET宏,在一次kevent调用中,更新多个感兴趣的文件描述符状态。

使用上:kevent所允许过滤的事件,除了select/poll/epoll所关注的文件I/O和超时外,还有异步I/O,文件修改通知,进程跟踪和信号处理。与此同时,epoll不支持监听普通文件或目录的文件描述符。

4.多进程 VS 多线程:

多进程——缺点

01. 创建及维护进程对系统来说都有开销——启动进程需要时间,而操作系统必须投入内部资源来管理进程

02. 一般来说子进程需要使用某种IPC机制来通知父进程有关I/O操作的状态,而进程之间的通信通常设置复杂,或是速度较慢,或者兼而有之——因为操作系统通常在进程间提供了大量保护,以避免一个进程不小心修改了另一个进程的数据

多进程——优点

01.操作系统在进程间提供的附加保护操作和更高级别的通信机制,意味着可以比线程更容易地编写安全的并发代码

02.你可以通过网络连接的不同的机器上运行独立的进程,在某些情况下,这是一个提高并行可用性和提高性能的低成本方法

多线程——缺点

如果数据要被多个线程访问,那么开发者就必须确保当每个线程访问时所看到的数据是一致的(即线程同步),这将使编程工作变得复杂,尤其是如果我们使用线程池技术来最小化需要处理的大量并发客户的线程数量时

多线程——优点

共享的地址空间,以及缺少线程间的数据保护,使得使用多线程相关的开销远小于使用多进程——操作系统有更少的簿记要做

对于C++来说,C++标准并没有为进程间通信提供任何原生支持,所以使用多进程的应用程序将不得不依赖平台相关的API来实现

5.epoll 水平触发通知. vs .边缘触发通知 (两种文件描述符准备就绪的通知模式)

水平触发通知(LT notification):如果文件描述符上可以非阻塞地执行IO系统调用,此时认为它已经就绪

边缘触发通知(ET notification):如果文件描述符自上次状态检查以来有了新的IO活动(比如新的输入),此时需要触发通知

当采用水平触发通知时,我们可以在任意时刻检查文件描述符的就绪状态。由于水平触发模式允许我们在任意时刻重复检查IO状态,没有必要每次当文件描述符就绪后就需要尽可能多地执行IO。

当采用边缘触发通知时,只有当IO事件发生时我们才会收到通知。在另一个IO事件到来之前我们不会收到任何新的通知。所以对于采用边缘触发通知的程序,在接受到一个IO事件通知后,程序在某个时刻应该在相应的文件描述符上尽可能多地执行IO;如果程序采用循环来对文件描述符执行尽可能多地IO,则应当将文件描述符设置为非阻塞的,以防止最终当没有更多IO可执行时,IO系统调用会阻塞。

总的来看,ET模式在很大程度上降低了同一个epoll事件被重复触发的次数,因此效率比LT模式要高。

6.EPOLLONESHOT标志

对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多触发其上注册的一个可读、可写或者异常事件,且只触发一次,除非我们使用epoll_ctl函数重置该文件描述符上注册的EPOLLONESHOT事件。

一个用途就是确保一个socket连接在任一时刻只被一个线程处理。

References:

UNIX 网络编程,卷一

LINUX系统编程手册,下册

Linux高性能服务器编程

Linux系统编程温故知新系列 --- 01的更多相关文章

  1. Linux系统编程初探系列之一:文件编程

    系统函数 int creat(const char* filename,mode_t mode) filename:需要创建的文件名(包含路径,缺省为当前路径) mode:创建模式 常见的创建模式有: ...

  2. LINUX系统编程 由REDIS的持久化机制联想到的子进程退出的相关问题

    19:22:01 2014-08-27 引言: 以前对wait waitpid 以及exit这几个函数只是大致上了解,但是看REDIS的AOF和RDB 2种持久化时 均要处理子进程运行完成退出和父进程 ...

  3. 读书笔记之Linux系统编程与深入理解Linux内核

    前言 本人再看深入理解Linux内核的时候发现比较难懂,看了Linux系统编程一说后,觉得Linux系统编程还是简单易懂些,并且两本书都是讲Linux比较底层的东西,只不过侧重点不同,本文就以Linu ...

  4. linux系统编程:cp的另外一种实现方式

    之前,这篇文章:linux系统编程:自己动手写一个cp命令 已经实现过一个版本. 这里再来一个版本,涉及知识点: linux系统编程:open常用参数详解 Linux系统编程:简单文件IO操作 /*= ...

  5. Linux 系统编程 学习:01-进程的有关概念 与 创建、回收

    Linux 系统编程 学习:01-进程的有关概念 与 创建.回收 背景 上一讲介绍了有关系统编程的概念.这一讲,我们针对 进程 开展学习. 概念 进程的身份证(PID) 每一个进程都有一个唯一的身份证 ...

  6. Linux 系统编程 学习:07-基于socket的网络编程2:基于 UDP 的通信

    Linux 系统编程 学习:07-基于socket的网络编程2:基于 UDP 的通信 背景 上一讲我们介绍了网络编程的一些概念.socket的网络编程的有关概念 这一讲我们来看UDP 通信. 知识 U ...

  7. Linux系统编程【3.2】——ls命令优化版和ls -l实现

    前情提要 在笔者的上一篇博客Linux系统编程[3.1]--编写ls命令中,实现了初级版的ls命令,但是与原版ls命令相比,还存在着显示格式和无颜色标记的不同.经过笔者近两天的学习,基本解决了这两个问 ...

  8. linux系统编程之错误处理

    在linux系统编程中,当系统调用出现错误时,有一个整型变量会被设置,这个整型变量就是errno,这个变量的定义在/usr/include/errno.h文件中 #ifndef _ERRNO_H /* ...

  9. Linux系统编程-setitimer函数

    功能:linux系统编程中,setitimer是一个经常被使用的函数,可用来实现延时和定时的功能. 头文件:sys/time.h 函数原型: int setitimer(int which, cons ...

随机推荐

  1. What's going on in background?

    Did you know that mobile phone manufacturer collect your info without notifying you? Did you know yo ...

  2. 【转】Java集合类

    http://blog.csdn.net/zhangerqing/article/details/8122075 http://android.blog.51cto.com/268543/400557 ...

  3. python学习:环境搭建

    1.图解eclipse环境下安装python3.x插件支持:http://www.tuicool.com/articles/M3Afyu 其中如果 然后,选择Add按钮,Name:Python3,Lo ...

  4. Verilog $random用法

    “$random函数调用时返回一个32位的随机数,它是一个带符号的整形数...”,并给出了一个例子: _________________________________________________ ...

  5. 转换,2D,3D

    一,转换定义: 1,能够改变元素的形状,尺寸,位置 2,转换分两种: 2D转换:只能在X,Y轴发生改变: 例子:旋转(rotate).拉伸(scale).平移(move).倾斜(skew) 3D转换: ...

  6. 转 LoadRunner 技巧之THML 与 URL两种录制模式分析

    Loadrunner的Virtual User Generator 提供人脚本的录制功能,对于初学者来说,这大大的降低了编写脚本的门槛,loadrunner提供两种录制脚本的方式:Html_based ...

  7. Windows Server 2008下asp+access无法登陆问题总结

    今日把一套陈旧的企业办公平台部署至公司新采购的服务器,因为在本机windows7环境已经反复测试通过.本以为分分钟完成的事情,结果折腾了我2天.服务器系统:windows server 2008 r2 ...

  8. 关于nginx的1W并发的优化

    我们来看一下图,下面的这张图清晰的表明了nginx优化的一些方法: nginx要响应请求的话,必须要: 1.要建立socket连接 2.是要读本地的文件 所以这就是我们的一个优化的方向: 所以参考照上 ...

  9. prolog --寻找neni (2)

    混合查询 我们可以把简单的查询连接起来,组成复杂的查询. ?- location(X,kitchen),edible(X). 简单查询只有一个目标,而混合查询可以把这些目标连接起来.从而进行较为复杂的 ...

  10. nodeJs中创建服务器

    var http=require('http'); var httpObj=http.createServer(function(req,res) { console.log('someBody:' ...