《Unix网络编程》读书笔记

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分节告知),也可以设置此值,但不是所有系统都支持,并且只能减少其值,不能增加其值。
  1. TCP_NODELAY (重点)
    禁止Nagle算法(重点看书172页和资料)

第16章 非阻塞IO

16.1 概述

可能阻塞的套接口调用可分为四类:
(1)输入操作:read, readv, recv, recvfrom, recvmsg,当对一个阻塞的TCP套接口(缺省设置),调用这些函数,而且该套接口对应的接收缓冲区没有数据可读时,该进程投入睡眠,知道到达一些数据;
对于UDP, 若它的接收缓冲区为空,一样会投入睡眠;
对于非阻塞,如果输入操作不能满足(tcp为一个字节,UDP为一个完整的数据报可读),相应调用将立即返回一个EWOULDBLOCK错误;

(2)输出操作:包括write, writev, send, sendto和sendmsg, 对于阻塞的套接口,如果其发送缓冲区没有空间,将睡眠;
对于一个非阻塞的TCP, 如果发送缓冲区没有空间,则返回一个EWOULDBLOCK错误;
UDP不存在真正的发送缓冲区,因此不会想tcp一样阻塞,但会因其他原因阻塞;

(3)accept函数,在连接未到来之前,阻塞的套接口会投入睡眠,而非阻塞的会立即返回一个EWOULDBLOCK错误;

(4)connect函数, connect必须要等到它收到对于自己的SYN的ACK才会返回,这意味着connect总是阻塞进程至少一个到服务器的RTT时间

16.2 非阻塞的读和写(先过吧,是一个例子)

16.3非阻塞connect

你可能感兴趣的:(《Unix网络编程》读书笔记)