原文: http://cstdlib.com/tech/2014/10/09/read-unix-network-programming-1/

文章写的很清楚, 适合初学者

最近看了《UNIX网络编程 卷1:套接字联网API》, 英文名叫Unix Network Programming啦,后来上网查了查, 一般都叫UNP逼格会高一点, 就像APUE一样。 他们的作者都是W. Richard Stevens。 另外,他也是TCP/IP Illustrated的作者。 靠,看完作者简介,简直崇拜得五体投地了。

说说这本书中比较让我印象深刻的内容吧,我只看了书中关于关于TCP和UDP的主要部分,略过了一些章节,所以可能有一些遗漏。

  • TCP和UDP的工作过程
  • TCP连接在“非正常”情况下的工作状况
  • 各种I/O模型(阻塞/非阻塞/IO复用/信号驱动/异步)
  • 守护进程和inetd的工作原理
  • 服务器程序设计范式
  • 客户端程序设计范式

TCP和UDP的工作过程

UDP的工作过程是简单的,仅仅将用户数据封装到一个IP数据报中发送到目的地而已,而不关注其他方面。

TCP却是一个极其复杂的协议,以下只是冰山一角

  • 建立连接的三次握手
    1. 主动方发送(SYN J),进入SYN_SENT状态
    2. 被动方收到(SYN J),并往回发送(SYN K, ACK J+1),进入SYN_RCVD状态
    3. 主动方收到(SYN K, ACK J+1),并往回发送(ACK K+1),进入ESTABLISHED状态
    4. 被动方收到(ACK K+1),也进入ESTABLISHED状态

    以上过程如下图所示:

    注意到在TCP三次握手的过程中,服务器有这么一条:

    2. 被动方收到(SYN J),并往回发送(SYN K, ACK J+1),进入SYN_RCVD状态

    服务器进入SYN_RCVD状态(此时连接称为半开连接)后,应当期待再收到一个ACK。 如果超时未收到客户端的ACK,服务器将重发(SYN K, ACK J+1)。 于是,就有一种叫做SYN Flooding的攻击方式。 攻击者向服务器高速发送(SYN J)(而且可以将SYN分节中的IP地址设为随机数), 并且在随后收到服务器回复的(SYN K, ACK J+1)之后不再继续回复, 这使得服务器上存在很多的半开连接,这些半开连接一般情况下会持续63秒 (在Linux下,默认重试次数为5次,重试的间隔时间从1s开始每次都翻倍,5次的重试时间间隔为1s, 2s, 4s, 8s, 16s,第5次发出后还要等32s都知道第5次也超时了,所以,总共需要 1s + 2s + 4s+ 8s+ 16s + 32s = 63s,TCP才会把断开这个连接)。 它的危害有两方面,一方面自然是占用了服务器的资源;另一方面是填充了半开连接的队列,使得合法的SYN分节无法排队。

    根据SYN Flooding的攻击原理,它的防范主要有以下措施:

    1. 过滤掉最大嫌疑攻击的IP或IP段
    2. tcp_synack_retries设为0,表示回应第二个握手包(SYN K, ACK J+1)给客户端后,如果收不到ACK,不进行重试,加快回收“半开连接”。
    3. tcp_max_syn_backlog参数根据内存情况适当调大,该参数一般指的是维护的半开连接的队列的长度(不同OS不一样)。
    4. 设置tcp_abort_on_overflow选项,处理不过来就直接拒绝掉。
  • 断开连接的四次握手
    1. 主动方发送(FIN M),进入FIN_WAIT_1状态
    2. 被动方收到(FIN M),并往回发送(ACK M+1),进入CLOSE_WAIT状态
    3. 主动方收到(ACK M+1),进入FIN_WAIT_2状态
    4. 被动方发送(FIN N),进入LAST_ACK状态
    5. 主动方收到(FIN N),并往回发送(ACK N+1),进入TIME_WAIT状态
    6. 被动方收到(ACK N+1),进入CLOSED状态
    7. 主动方在TIME_WAIT状态中超时后,进入CLOSED状态

    以上过程如下图所示:

    其实就是2次,只不过TCP是全双工的,所以,发送方和接收方都需要FIN和ACK。 只不过,有一方是被动的,所以看上去就成了所谓的4次挥握手。

    注意到最后有这么一条涉及到TIME_WAIT的状态

    7. 主动方在TIME_WAIT状态中超时后,进入CLOSED状态

    需要经过一个TIME_WAIT超时的状态而不是直接进入CLOSED的原因有两个,一是确保有足够的时间让对端收到ACK,二是允许老的分节在网络中慢慢的消逝。

    然而,如果系统中存在着大量的短链接,那么大量的TIME_WAIT状态就会成为系统的累赘。网上一些资料提到的tcp_tw_reusetcp_tw_recycle选项来解决这个问题,但是最好还是别乱用,好像coolshell中有提到过,可能会出很多诡异的问题。还可以调整tcp_max_tw_buckets,当并发的TIME_WAIT过多时,会直接把多的给destory掉,然后在日志里打一个警告。引用一句“其实,TIME_WAIT表示的是你主动断连接,所以,这就是所谓的no zuo, no die”。

TCP连接在“非正常”情况下的工作状况

  • 服务器进程终止

    首先,服务器进程终止(收到SIGKILL信号)。作为进程中止处理的工作之一,该进程所有打开着的描述符将被关闭,这会导致向对端(客户端)发送(FIN N),而客户端则回复(ACK N+1),这就是TCP断开连接的前半部分。

    然后,此时客户端收到(FIN N)并不意味着连接断开(虽然在这个例子中,确实断开了),只是意味着服务器不再向客户端发送数据了,客户端还可以继续向服务器发送数据。如果此时客户端还继续向服务器发送数据,服务器TCP将发现之前的打开该套接字的进程已终止,于是回应一个RST。客户端在收到这个RST之前的read操作将会返回EOF,在收到这个RST后的read操作会返回ECONNRESET错误,在收到这个RST后的write操作会使当前进程收到SIGPIPE信号。

    以上过程如下图所示:

  • 服务器主机崩溃

    服务器主机崩溃的意思是,没有任何预兆,来不及在网络上发送任何消息,主机就无法工作了。这种情况等价于直接切断网络,或者通俗的说,可以直接拔掉网线来模拟这一情况。

    这时,如果客户端向服务器发送数据,后调用read操作,TCP会一直等待服务器的ACK确认消息,并且不断的超时重传(按照Berkeley的实现,重传12次,共需9分钟),直到到达重传次数,返回ETIMEOUT错误。如果是由中间的路由器判定服务器主机不可达,响应“destination unreasonable”的ICMP消息,将返回EHOSTUNREACHENETUNREACH错误。

  • 服务器主机崩溃后重启

    重启之后的服务器已经丢失了之前的TCP信息,所以即使收到了客户端发来的TCP数据,也会回复RST,往后的情况和“服务器主机崩溃”中提到的类似。

  • 服务器主机关机

    Unix系统关机时,init进程通常会给其他进程发送SIGTERM信号,然后等待10s左右给仍在运行的进程发送SIGKILL信号。所以如果进程不捕获SIGTERM信号,则将由SIGKILL信号终止,和“服务器进程终止”中提到的类似。

再往后的I/O模型、守护进程和inetd的工作原理、服务器程序设计范式、客户端程序设计范式过几天有时间再写吧。

[转载] 读《UNIX网络编程 卷1:套接字联网API》的更多相关文章

  1. Unix网络编程--卷一:套接字联网API

    UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...

  2. UNIX网络编程——基本TCP套接字编程

    一.基于TCP协议的网络程序 下图是基于TCP协议的客户端/服务器程序的一般流程: 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听端口的 ...

  3. 【Unix网络编程】chapter3套接字编程简介

    chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...

  4. 【Unix网络编程】chapter3 套接字编程简介

    chapter3套接字编程简介3.1 概述 地址转换函数在地址的文本表达和他们存放在套接字地址结构中的二进制值之间进行转换.多数现存的IPv4代码使用inet_addr和inet_ntoa这两个函数, ...

  5. Unix网络编程 高级IO套接字设置超时

    我们知道.对于一个套接字的读写(read/write)操作默认是堵塞的.假设当前套接字还不可读/写,那么这个操作会一直堵塞下去,这样对于一个须要高性能的server来说,是不能接受的.所以,我们能够在 ...

  6. 【Unix网络编程】chapter7套接字选项

    7.1 概述 有很多方法来获取和设置影响套接字的选项: getsockopt和setsockopt函数 fcntl函数 ioctl函数 7.2 getsockopt和setsockopt函数 7.3 ...

  7. UNIX网络编程 卷2:进程间通信

    这篇是计算机类的优质预售推荐>>>><UNIX网络编程 卷2:进程间通信(第2版)> UNIX和网络专家W. Richard Stevens的传世之作 编辑推荐 两 ...

  8. 《UNIX网络编程 卷1》之"学习环境搭建"(CentOS 7)

    <UNIX网络编程 卷1>的源码可以从www.unpbook.com下载得到.解压之后的目录为unpv13e. 详细步骤 编译 进入unpv13e目录,按如下步骤编译: ./configu ...

  9. VC++学习之网络编程中的套接字

    VC++学习之网络编程中的套接字 套接字,简单的说就是通信双方的一种约定,用套接字中的相关函数来完成通信过程.应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问 ...

随机推荐

  1. PHP建站通过服务器架构及实战的方法

    PHP的环境搭建 PHP的帮助使用和配置文件 PHP的Hello World PHP的库函数调用 PHP的Web程序 PHP的函数和面向对象使用 PHP的数据库访问 Nginx安装和配置访问 Word ...

  2. JavaEE基础(十)

    1.面向对象(package关键字的概述及作用) A:为什么要有包 将字节码(.class)进行分类存放 包其实就是文件夹 B:包的概述 举例: 学生:增加,删除,修改,查询 老师:增加,删除,修改, ...

  3. C# winform 中MessageBox用法大全(附效果图) (转载+说明)

    声明:这篇文章是转载的转载的,由于原作者的博客被关闭 我就不再列出了,提前先说明下,if语句中的判断有些太长,建议提前声明一个变量, DialogResult MsgBoxResult;        ...

  4. ecshop后台增加模板页的方法

    CShop的动态模板机制是一个非常灵活的系统,管理员可以在后台根据自己的要求调整模板模块的显示位置.本文详细讲解了如何修改ECSHOP内部结构使得用户可以添加自己的模板页从而方便灵活的使用系统自带的模 ...

  5. java 练习题

    题目:想控制台输1-3个整数,按顺序为年,月,日.#号键结束输入.若输入一个整数,则为年份,程序判断是闰年还是平年:若输入两个整数,则为年份和月份,程序将输出该年的月份的天数:若输入3个整数:则为年, ...

  6. 20150618_Andriod_设置TextView垂直滚动

    布局文件 android:scrollbars="vertical" android:singleLine="false" 代码文件 ctl_tv_conten ...

  7. Radar Installation 分类: POJ 2015-06-15 19:54 8人阅读 评论(0) 收藏

    Radar Installation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 60120   Accepted: 13 ...

  8. 修改Netbeans默认使用UTF-8编码

    NetBeans是一款优秀的开源集成开发环境,可以用于Java,C/C++,PHP等语言的开发.同时它也是一个可扩展的开发平台,可以通过插件来扩展官方版本没有的功能.自从被Oracle这个开源杀手收购 ...

  9. 嵌入式学习_AD学习篇

    AD基础使用: 1.建立一个工作区 (.DsnWrk) workspace 2.建立一个PCB工程(.PrjPCB)  project 3.建立一个PCB原理图文件(理论上告诉你两个点连接起来) 建立 ...

  10. VC++打开对话框选择一个文件夹路径 BROWSEINFO结构

    typedef struct _browseinfoW { HWND hwndOwner; PCIDLIST_ABSOLUTE pidlRoot; LPWSTR pszDisplayName; // ...