《Unix网络编程》读书笔记(一)

来源:互联网 发布:mac dns污染 编辑:程序博客网 时间:2024/06/05 19:18

TCP各大问题:
1.nagle算法;
2.延迟确认
3.滑动窗口;
4.time_wait状态;
5.MSS, MTU, WIN区别;
6.慢启动;
7.关闭,半关闭;
8.epoll和select的区别

第二章
2.3 UDP
1.UDP不保证数据报最终会到达目的地,不保证各个数据报的先后循序跨网络后保持不变,也不保证每个数据包只到达一次。
2.UDP,如果一个数据包到达目的地,但校验有错误,或者数据包在中途被丢弃,它就无法投递给UDP套接字,也不会被源端重传。

2.4 TCP
1.TCP会对发送的数据进行排序,并可以丢弃重复数据。
2.MSS:MSS在发送SYN时通告,它告诉对方每个TCP分节能接受的最大字节数,它一般等于MTU减去IP和TCP首部的固定长度;
3.WIN:窗口大小,其实就是当前接收缓冲区的可用的空间量。每个分节都会告诉对方。最大值是65535;
4.TIME_WAIT解释:见第37页;

2.9端口号
1. 0~1023为众所周知的端口号;

2.11 TCP缓冲区大小及限制
1.当一个IP数据包超过相应链路的MTU时,会被分片;
2.每个TCP套接字都有一个发送缓冲区,可用SO_SNDBUF套接字更改大小;
3.当调用write时,内核从应用缓冲区复制所有数据到发送缓冲区,若发送缓冲区大小不够,则默认阻塞;
4.从write调用成功返回仅仅表示可以重新使用原来的应用进程缓冲区,并不表明对端的TCP或应用进程已接收到数据。

2.11.2 UDP输出
1.UDP实际上并不存在发送缓冲区,任何UDP套接字都有发送缓冲区大小,不过它仅仅是可写到该套接字的UDP数据包的大小上限。若超过上限则返回一个EMSGSIZE错误。

第三章
3.9 readn,wiriten和readline函数
1.每读一个字节就调用一次read函数,是非常低效的;
2.如果使用io函数库,stdio缓冲机制会引发很多问题,因为stdio缓冲区的状态是不可见的,无法分辨stdio缓冲区是否持有未预期的数据;
3.可以自己实现readline函数,让缓冲区暴露出来,但是如果写的不严谨,很可能会发现自己在select上等待的数据早已收到并存放在readline的缓冲区中了。(个人理解,如,当用select时,读了一次缓冲区数据,但是没有读完时,剩下的数据不能再触发一次读操作)。

第四章
4.3 connect函数
1.connect前不必调用bind;
2.connect将触发tcp的三路握手过程;
3.若没有收到SYN相应,会重发,75s后仍未收到,则返回ETIMEDOUT错误;
4.若对客户的SYN的响应是RST, 则表明该服务器主机在我们指定的端口上没有进程在等待。客户已收到RST会马上返回ECONNREFUSED错误;
5.RST产生的三个条件:目的地为某端口的SYN到达,然而该端口上没有正在监听的服务器;TCP想取消一个已有连接(这个不懂);TCP接收到一个根本不存在的连接上的分节。
6.若发出的SYN中间的某个路由器上引发了一个“destination unreachable”(目的地不可达)ICMP错误,则认为是一种软错误,并重发。

4.4 bind函数
1.bind函数可以指定一个端口号,或一个ip地址,也可以两者都指定,还可以都不指定;

4.5 listen函数
1.socket函数创建的套接字默认为主动套接字,listen函数把一个未连接的套接字转换为一个被动套接字;
2.backlog,详情看84页;

4.6 accept函数
1.accept函数,第一个参数为监听套接字,返回值为已连接套接字,区分两者很重要;
2.accept成功,说明已完成tcp三路握手;

4.7 fork和exec函数
1.exec把当前进程映像替换成新的程序文件,新程序通常从main函数开始执行;

4.8 并发服务器
见书中92~93页那几个图

4.9 close函数
1.close一个tcp套接字默认行为是把该套接字标记成已关闭,该套接字不能再用来read或write;
2.并发服务器中父进程close已连接套接字只是导致相应描述符的引用计数值减1,如果引用计数值仍大于0,这个close调用并不引发TCP的四分组终止序列;

第五章
5.7 正常终止
1.进程终止处理的部分工作是关闭所有打开的描述符,这会导致tcp发送一个FIN给服务器(在描述符引用计数为0的情况下);

5.8 POSIX信号处理
1.SA_RESTART标志,如果设置,则由相应信号中断的系统调用将由内核自动重启

5.9 处理SIGCHLD信号
1.警告:在信号处理函数中调用诸如printf这样的标准IO函数是不合适的,原因将在11.18节讨论。
2.如果一个信号实在进程阻塞于慢系统调用(accept)时被捕获,内核就会时accept返回一个EINTR错误,如果设置了SA_RESTART标志,则内核将重启被中断的系统调用,accept不会返回错误。
3.处理被中断的系统调用的方法,详见108页;

5.11 accept返回前连接中止
1.具体看111页
2.从这里可以看出,服务器在调用listen后,客户端若发出connect,就可以进行三路握手了(不必等到服务器调用accept),完成握手后进入已连接队列,等待服务器accept取走;

5.12 服务器进程终止
1.客户TCP接收到FIN只是表示服务器不再往其中发送任何数据而已,FIN的接收并没有告知客户TCP服务器进程已经终止;
2.当服务器TCP接收到来自客户的数据(客户write)时,如果该套接字的进程已经终止,则响应一个RST。
3.如果客户在收到RST之前调用了read, 则会收到一个EOF,否则read会返回一个ECONNRESET;

5.13 SIGPIPE信号
1.当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。该信号的默认行为是终止进程,因此进程必须捕获它以免不情愿被终止;
2.不论该进程是捕获了该信号并从其信号处理函数返回,还是简单地忽略该信号,写操作都将返回EPIPE错误。

5.14 服务器主机崩溃
1.若连接成功后,客户阻塞于read上,服务器崩溃,则客户TCP由于接收不到任何相应,会持续重传数据分节,试图接收到一个ACK,共等待约9分钟才放弃重传,并给客户进程返回一个错误;
2.可以对read设置超时,在14.2讨论;
3.如果我们想不主动向它发送数据也想检测服务器主机的崩溃,可以用SO_KEEPALIVE选项;

5.15 服务器主机崩溃后重启
1.客户和服务器之间建立连接,然后服务器主机崩溃并重启,那么客户如果在服务器崩溃时不主动发送数据给服务器,那么客户将不知道服务器崩溃;
2.当服务器重启后,收到客户的数据,则会相应一个RST;
3.可以使用SO_KEEPALIVE检测服务器崩溃。
5.16 服务器主机关机
1.unix系统关机时,init进程通常先给所有进程发送SIGTERM信号(该信号可被捕获),等待一段固定的时间(5到20秒),给所有仍在运行的进程发送SIGKILL信号,接下来就像5.12节那样。

第六章
6.1 概述
1.当要处理多个描述符时,必须使用IO复用;
2.还有几种IO复用的典型应用场合,详见122页;

6.2 I/O模型
详见123页,要认真搞清楚;

6.3 select函数
1.描述符就绪条件,详见130页;
2.select的例子,需要再看吧;

6.6 shutdown函数
1.shutdown可以不管引用计数就激发TCP正常连接终止序列;
2.shundown可以关闭读或写两个方向;

第七章
7.5 通用套接字选项
1.SO_BROADCAST
只有UDP才支持,应用进程在发送广播数据包前必须设置该选项;

2.SO_DEBUG 先不管

3.SO_DONTROUTE 不懂,先不管吧

4.SO_ERROR
通过SO_ERROR选项可以获取so_error的值,由getsocktopt返回的整数值就是该套接字的待处理错误;

5.SO_KEEPALIVE
如果设置该选项,在2小时内该套接字任一方向没有数据交换,则自动一个保持存活探测分节,导致三种情况(详见157页)

6.SO_LINGER
更改close的默认操作

7.SO_OOBINLINE
带外数据相关,暂时不管
8.SO_RCVBUF和SO_SNDBUF
(1)每个套接字都有一个发送缓冲区和接收缓冲区;
(2)TCP套接字接收缓冲区不可能溢出,因为不允许对端发出超过本端所通告窗口大小的数据,如果对端无视窗口大小而发出超过窗口大小的数据,本端TCP将丢弃他们;
(3)对于UDP是没有流量控制的,当UDP接收缓冲区装不进数据时,就丢弃之;
(4)SO_RCVBUF必须在调用connect之前,对于服务器,必须在调用listen之前,因为窗口大小时通过连接时SYN分节得到的。
(5)TCP套接字缓冲区的大小至少应该是MSS值的四倍。

9.SO_RCVLOWAT和SO_SNDLOWAT
(1)接收低水位标记和发送低水位标记,由select函数使用;
(2)TCP的接收低水位默认为1,发送低水位为2048

10.SO_RCVTIMEO和SO_SNDTIMEO
接收和发送的超时值;

11.SO_REUSEADDR和SO_REUSEPORT
(1)SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将该端口用作它们的本地端口的连接仍存在,详情看165页;
(2)SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可;
(3)为安全起见,有些操作系统不允许对已经绑定了通配地址的端口再捆绑任何“更为明确的”地址,不论是否预设了SO_REUSEADDR;
(4)SO_REUSEADDR允许完全重复的捆绑,一般本特性仅支持UDP。如果该数据报的目的地址是一个广播或多播地址,那么给每个匹配的套接字一个副本,但如果该数据报的目的地址是一个单播地址,那它只递给单个套接字。
….还有一些,有空再研究

12.SO_TYPE
返回套接字的类型,诸如SOCK_STREAM或SOCK_DGRAM

13.SO_USELOOPBACK
先不管吧。

7.6 IPV4套接字选项
….先不管

7.9 TCP套接字选项
1.TCP_MAXSEG
本选项可以获取TCP的MSS(通常由对端使用SYN分节告知),也可以设置此值,但不是所有系统都支持,并且只能减少其值,不能增加其值。

2.TCP_NODELAY (重点)
禁止Nagle算法(重点看书172页和资料)