首页 > 代码库 > 《TCP/IP详解卷2:实现》笔记--TCP的用户需求

《TCP/IP详解卷2:实现》笔记--TCP的用户需求

本文介绍TCP的用户请求处理函数tcp_usrreq,它被协议的pr_usrreq函数调用,处理各种与tcp插口有关的系统调用,此外,

还将介绍tcp_ctloutput,应用进程调用setsockopt设定tcp插口选项时会用到它。

TCP的用户请求函数用于处理多种操作,主要由tcp_usrreq函数完成,函数的对各个请求的大概处理如下:

1.PRU_ATTACH请求。应用程序调用socket系统调用,或者监听服务器收到连接其你去,调用sonewconn函数,都会发出

PRU_ATTACH请求。如果插口结构已经指向某个PCB,则返回错误,调用tcp_attach完成处理:分配并初始化Internet PCB

和TCP控制块。

2.PRU_DETACH请求。close系统调用在PRU_DISCONNECT请求失败后,将发送PRU_DETACH请求,如果尚未建立连接,

则无需向对端发送任何信息,但如果连接已经建立,则调用tcp_disconnect初始化TCP的连接关闭过程。(发送所有缓存中

的数据,之后发送FIN)

3.PRU_BIND请求的处理只是简单地调用in_pcbbind。

4.对于PRU_LISTEN请求,如果插口还没有绑定到某个本地端口上,在调用in_pcbbind自动为其分配一个。连接状态变迁

到LISTEN,完成了listen调用的主要目的:设定插口的状态,以便接收到达的连接请求。

5.PRU_CONNECT请求。connect系统调用发起该请求,处理的大概流程如下:

a.分配临时端口。

b.连接PCB。

c.初始化IP和TCP首部。

d.计算窗口缩放因子。

e.设定插口和连接的状态。

f.初始化序号。

g.发送初始SYN。

5.PRU_CONNECT2请求。来自于socketpair系统调用,对TCP协议无效。

6.close系统调用会发送PRU_DISCONNECT请求。如果连接已经建立,应调用tcp_disconnect,发送FIN,执行正常的TCP

关闭操作。

7.与accept系统调用有关的工作全部由插口层和协议层完成。PRU_ACCEPT请求只简单地向应用进程返回对端的IP地址

和端口号。

8.PRU_SHUTDOWN请求。应用进程调用shutdown,禁止更多的输出时,soshutdown会发送PRU_SHUTDOWN请求。

调用socantsendmore置位插口标志,禁止继续发送报文段,接着调用tcp_usrclosed,设定正确的连接状态。

9.PRU_RCVD请求。应用进程从插口的接收缓存中读取数据后,soreceive会发送这个请求。此时接收缓存已扩大,也许

会有足够的空间,让TCP发送更大的窗口通告。tcp_output会决定是否需要发送窗口更新报文段。

10.PRU_SEND请求。调用sbappend,向插口的发送缓存中添加数据,并调用tcp_output发送新报文段(如果条件允许)。

11.PRU_ABORT请求。如果插口是监听插口,并且存在等待建立的连接,例如已发送初始SYN或已完成三次握手过程,但

还未被服务器accept的连接,调用soclose会导致发送PRU_ABORT请求。如果连接已同步,tcp_drop将发送RST。

12.PRU_SENSE请求。fastat系统调用会生成PRU_SENSE请求。TCP返回发送缓存的大小,保存在stat结构的成员变量中。

13.PRU_RCVOOB请求。当应用进程设置MSG_OOB标志,试图读取带外数据时,soreceive会发送这一请求。大概流程如下:

a.判断能否读取带外数据。

b.判断是否有带外数据到达。

c.返回带外数据字节。

d.更新标志。

e.确认发送缓存中有足够空间并添加新数据。

f.计算紧急指针。

g.强制TCP输出。

14.PRU_SOCKADDR请求。getsockname系统调用会发送该请求,调用in_setsockaddr函数。

15.PRU_PEERADDR请求。getpeername系统调用会发送该请求,调用in_setpeeraddr函数。调用in_setsockaddr和

in_setpeeraddr函数,从PCB中获取需要信息,存储在addr参数中。

16.执行tcp_slowtimo会发送PRU_SLOWTIMO函数。

《TCP/IP详解卷2:实现》笔记--TCP的用户需求