這裡蒐索程式師資訊,查找有用的技術資料
当前位置:首页 » 硬盘大全 » tcp接收缓存仅有数据存入
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

tcp接收缓存仅有数据存入

发布时间: 2022-04-23 01:49:46

⑴ 谁来讲解下TCP数据包的具体内容

TCP数据包结构:

1-1.源始端口16位,范围当然是0-65535。

1-2.目的端口,同上。

2-1.数据序号32位,TCP为发送的每个字节都编一个号码,这里存储当前数据包数据第一个字节的序号。

3-1.确认序号32位,为了安全,TCP告诉接受者希望他下次接到数据包的第一个字节的序号。

4-1.偏移4位,类似IP,表明数据距包头有多少个32位。

4-2.保留6位,未使用,应置零。

4-3.紧急比特URG—当URG=1时,表明紧急指针字段有效。它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)。

4-3.确认比特ACK—只有当ACK=1时确认号字段才有效。当ACK=0时,确认号无效。参考TCP三次握手。

4-4.复位比特RST(Reset) —当RST=1时,表明TCP连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新 建立运输连接。参考TCP三次握手。

4-5.同步比特SYN—同步比特SYN置为1,就表示这是一个连接请求或连接接受报文。参考TCP三次握手。

4-6.终止比特FIN(FINal)—用来释放一个连接。当FIN=1时,表明此报文段的发送端的数据已发送完毕,并要求释放运输连接。

4-7.窗口字段16位,窗口字段用来控制对方发送的数据量,单位为字节。TCP连接的一端根据设置的缓存空间大小确定自己的接收窗口 大小,然后通知对方以确定对方的发送窗口的上限。

5-1.包校验和16位,包括首部和数据这两部分。在计算检验和时,要在TCP报文段的前面加上12字节的伪首部。

5-2.紧急指针16位,紧急指针指出在本报文段中的紧急数据的最后一个字节的序号。

6-1.可选选项24位,类似IP,是可选选项。

6-2.填充8位,使选项凑足32位。

7-1.用户数据。

⑵ TCP的可靠性实现

TCP提供一种面向连接的、可靠的字节流服务。面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据包之前必须先建立一个TCP连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP。
TCP通过下列方式来提供可靠性:
1.应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据长度将保持不变。由TCP传递给IP的信息单位称为报文段或段(segment)。
2.当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。当TCP收到发自TCP连接另一端的数据,它将发送一个确认。TCP有延迟确认的功能,在此功能没有打开,则是立即确认。功能打开,则由定时器触发确认时间点。
3.TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
4.既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
5.既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。
6.TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(bytestreamservice)。如果一方的应用程序先传10字节,又传20字节,再传50字节,连接的另一方将无法了解发方每次发送了多少字节。只要自己的接收缓存没有塞满,TCP 接收方将有多少就收多少。一端将字节流放到TCP连接上,同样的字节流将出现在TCP连接的另一端。
另外,TCP对字节流的内容不作任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCⅡ字符、EBCDIC字符或者其他类型数据。对字节流的解释由TCP连接双方的应用层解释。
这种对字节流的处理方式与Unix操作系统对文件的处理方式很相似。Unix的内核对一个应用读或写的内容不作任何解释,而是交给应用程序处理。对Unix的内核来说,它无法区分一个二进制文件与一个文本文件。 TCP协议用于控制数据段是否需要重传的依据是设立重发定时器。在发送一个数据段的同时启动一个重传,如果在重传超时前收到确认(Acknowlegement)就关闭该重传,如 果重传超时前没有收到确认,则重传该数据段。在选择重发时间的过程中,TCP必须具有自适应性。它需要根据互联网当时的通信情况,给出合适的重发时间。
这种重传策略的关键是对定时器初值的设定。采用较多的算法是Jacobson于1988年提出的一种不断调整超时时间间隔的动态算法。其工作原理是:对每条连接TCP都保持一个 变量RTT(Round Trip Time),用于存放当前到目的端往返所需要时间最接近的估计值。当发送一个数据段时,同时启动连接的定时器,如果在定时器超时前确认到达,则记录所需要的时间(M),并修正 RTT的值,如果定时器超时前没有收到确认,则将RTT的值增加1倍。通过测量一系列的RTT(往返时间)值,TCP协议可以估算数据包重发前需要等待的时间。在估计该连接所需的当前延迟时通常利用一些统计学的原理和算法(如Karn算法),从而得到TCP重发之前需要等待的时间值。 TCP的一项功能就是确保每个数据段都能到达目的地。位于目的主机的TCP服务对接受到的数据进行确认,并向源应用程序发送确认信息。
使用数据报头序列号以及确认号来确认已收到包含在数据段的相关的数据字节。
TCP在发回源设备的数据段中使用确认号,指示接收设备期待接收的下一字节。这个过程称为期待确认。
源主机在收到确认消息之前可以传输的数据的大小称为窗口大小。用于管理丢失数据和流量控制。这些变化如右图所示。 修改建立TCP连接的超时时间
建立TCP连接需要经过三次握手:主动端先发送SYN报文,被动放回应SYN+ACK报文,然后主动端再回应ACK。
l在主动端发送SYN后,如果被动端一直不回应SYN+ACK报文,主动端会不断的重传SYN报文直到超过一定的重传次数或超时时间。
l在主动端发送SYN后,被动端回应SYN+ACK报文,但主动端不再回复ACK,被动端也会一直重传直到超过一定的重传次数或超时时间。(SYN报文攻击会出现这种情况)
可以通过以下命令配置SYN报文的超时时间(发送SYN报文到三次握手成功的最大时间),也就是建立TCP连接的超时时间。 命令 作用 R(config)#ip tcp syntime-out seconds 修改建立TCP连接的超时时间。
单位秒,取值范围5-300,缺省值20 使用no ip tcp syntime-out命令恢复参数缺省值。
修改缓冲区大小
TCP的接收缓冲区是用来缓存从对端接收到的数据,这些数据后续会被应用程序读取。一般情况下,TCP报文的窗口值反映接收缓冲区的空闲空间的大小。对于带宽比较大、有大批量数据的连接,增大接收缓冲区的大小可以显着提供TCP传输性能。TCP的发送缓冲区是用来缓存应 用程序的数据,发送缓冲区的每个字节都有序列号,被应答确认的序列号对应的数据会从发送缓冲区删除掉。增大发送缓冲区可以提高TCP跟应用程序的交互能力,也因此会提高性能。但是增大接收和发送缓冲区会导致TCP占用比较多的内存。 命令 作用 R (config)#ip tcp window-size size 修改TCP连接的接收和发送缓冲区大小。
单位字节,取值范围0-65535,缺省值4096。 使用no ip tcp window-size命令恢复接收和发送缓冲区大小为缺省值。
禁止端口不可达时的重置报文
TCP模块在分发TCP报文时,如果找不到该报文所属的TCP连接会主动回复一个reset报文以终止对端的TCP连接。攻击者可能利用大量的端口不可达 的TCP报文对设备进行攻击。
可以使用以下命令禁止/恢复在收到端口不可达的TCP报文时发送reset报文。 命令 作用 R (config)#ip tcp not-send-rst 禁止在接收到端口不可达的TCP报文时发送reset报文。 使用no ip tcp not-send-rst命令恢复发送reset报文。
限制TCP连接的MSS的最大值
MSS是最大传输段大小的缩写,指一个TCP报文的数据载荷的最大长度,不包括TCP选项。
在TCP建立连接的三次握手中,有一种很重要的工作那就是进行MSS协商。连接的双方都在SYN报文中增加MSS选项,其选项值表示本端 最大能接收的段大小,即对端最大能发送的段大小。连接的双方取本端发送的MSS值和接收对端的MSS值的较小者作为本连接最大传输段大小。
发送SYN报文时的MSS选项值的计算方法如下。
l非直连网络中:mss = 默认值 536。
l直连网络中:mss = 对端ip地址对应的出口的MTU - 20字节ip头 - 20字节tcp头。一般来说如果出口配置的某些应用影响了接口的mtu,那么该应用会相应的设置mtu,如隧道口,vpn口等。
到这里得到的rmss值就是要发送的syn报文mss选项的值 。举例:一般情况下在直连网络中建立bgp邻居,那么该连接的发送的mss为1500 – 20 – 20 – 20 = 1440。
ip tcp mss命令的作用是限制即将建立的TCP连接的MSS的最大值。任何新建立的连接协商的MSS值不能超过配置的值。 命令 作用 R (config)#ip tcp mss max-segment-size 限制TCP连接的MSS的最大值。
单位为字节,取值范围68-10000。 使用no ip tcp mss命令取消此限制。
启用PMTU发现功能
TCP的路径最大传输单元(PMTU)发现功能是按RF C1191实现的,这个功能可以提高网络带宽的利用率。当用户使用TCP来批量传输大块数据时,该功能可以使传输性能得到明显提升。 命令 作用 R(config)#ip tcp path-mtu-discovery [ age-timer minutes| age-timer infinite ] 启用PMTU发现功能。
age-timer minutes:TCP在发现PMTU后,重新进行探测的时间间隔。单位分钟,取值范围10-30。缺省值10。
age-timer infinite:TCP在发现PMTU后,不重新探测。 按RFC1191的描述,TCP在发现PMTU后,隔一段时间可以使用更大的MSS来探测新的PMTU。这个时间间隔就是使用参数age-timer来指定。当设备发现的PMTU比TCP连接两端协商出来的MSS小时,设备就会按上述配置时间间隔,去尝试发现更大的PMTU。直到PMTU达到MS S的值,或者用户停止这个定时器,这个探测过程才会停止。停止这个定时器,使用age-timer infinite参数。
使用no ip tcp path-mtu-discovery命令关闭PMTU发现功能。
设置接口收发SYN报文的MSS选项值
当客户端发起一个TCP连接时,它通过TCP SYN报文中的MSS选项字段协商TCP报文数据载荷的最大值,客户端SYN报文的MSS值表示后续服务器端发送TCP报文数据载荷的最大值,反之同理。
如右图的拓扑,PC用http访问服务器可能会出现无法访问的情况。因为PC与服务器端建立的连接MSS协商的都会是1460,但1460的MSS无法通过R1和R2,R1和R2用隧道相连,MTU小于1500。
这时可以通过在R2的(1)口和(2)口上配置如下命令,修改SYN报文中的MSS选项值。从而修改经过(1)口和(2)口的TCP连接协商的MSS值。 命令 作用 R (config-if)# ip tcp adjust-mssmax-segment-size 设置接口收发SYN报文的MSS选项值。
单位为字节,取值范围500-1460。 使用no ip tcp adjust-mss命令取消此项设置,则接口收发SYN报文时,不会修改报文的MSS选项值。
在接口上配置本命令会使得该接口接收或发送SYN报文的MSS选项都被改为接口上配置的MSS值。建议出口和入口配置相同的值。如果SYN报文的入口和出口配置了不同的MSS值,经过该设备后,SYN报文的MSS选项被改为这两个口配置值的较小者。

⑶ linux tcp 通过setsockopt设置接收缓存区有什么用

Socket的send函数在执行时报EAGAIN的错误

当客户通过Socket提供的send函数发送大的数据包时,就可能返回一个EGGAIN的错误。该错误产生的原因是由于send 函数中的size变量大小超过了tcp_sendspace的值。tcp_sendspace定义了应用在调用send之前能够在kernel中缓存的数据量。当应用程序在socket中设置了O_NDELAY或者O_NONBLOCK属性后,如果发送缓存被占满,send就会返回EAGAIN的错误。

为了消除该错误,有三种方法可以选择:
1.调大tcp_sendspace,使之大于send中的size参数
---no -p -o tcp_sendspace=65536

2.在调用send前,在setsockopt函数中为SNDBUF设置更大的值

3.使用write替代send,因为write没有设置O_NDELAY或者O_NONBLOCK

1. tcp 收发缓冲区默认值

[root@qljt core]# cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4161536

87380 :tcp接收缓冲区的默认值

[root@qljt core]# cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4161536

16384 : tcp 发送缓冲区的默认值

2. tcp 或udp收发缓冲区最大值

[root@qljt core]# cat /proc/sys/net/core/rmem_max
131071

131071:tcp 或 udp 接收缓冲区最大可设置值的一半。

也就是说调用 setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 时rcv_size 如果超过 131071,那么

getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen); 去到的值就等于 131071 * 2 = 262142

[root@qljt core]# cat /proc/sys/net/core/wmem_max
131071

131071:tcp 或 udp 发送缓冲区最大可设置值得一半。

跟上面同一个道理

3. udp收发缓冲区默认值

[root@qljt core]# cat /proc/sys/net/core/rmem_default
111616:udp接收缓冲区的默认值

[root@qljt core]# cat /proc/sys/net/core/wmem_default
111616

111616:udp发送缓冲区的默认值

. tcp 或udp收发缓冲区最小值

tcp 或udp接收缓冲区的最小值为 256 bytes,由内核的宏决定;

tcp 或udp发送缓冲区的最小值为 2048 bytes,由内核的宏决定

setsockopt设置socket状态
1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:
BOOL bReuseaddr=TRUE;
setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL));

2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭,不经历TIME_WAIT的过程:
BOOL bDontLinger = FALSE;
setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char*)&bDontLinger,sizeof(BOOL));

3.在send(),recv()过程中有时由于网络状况等原因,发收不能预期进行,而设置收发时限:
int nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));

4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));

5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));

6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));

7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));

8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显着的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char*)&bConditionalAccept,sizeof(BOOL));

9.如果在发送数据的过程中(send()没有完成,还有数据没发送)而调用了closesocket(),以前我们一般采取的措施是"从容关闭"shutdown(s,SD_BOTH),但是数据是肯定丢失了,如何设置让程序满足具体应用的要求(即让没发完的数据发送出去后在关闭socket)?
struct linger {
u_short l_onoff;
u_short l_linger;
};
linger m_sLinger;
m_sLinger.l_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为5秒)
setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));

设置套接口的选项。
#include <winsock.h>
int PASCAL FAR setsockopt( SOCKET s, int level, int optname,
const char FAR* optval, int optlen);
s:标识一个套接口的描述字。
level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval缓冲区的长度。
注释:
setsockopt()函数用于任意类型、任意状态套接口的设置选项值。尽管在不同协议层上存在选项,但本函数仅定义了最高的“套接口”层次上的选项。选项影响套接口的操作,诸如加急数据是否在普通数据流中接收,广播数据是否可以从套接口发送等等。
有两种套接口的选项:一种是布尔型选项,允许或禁止一种特性;另一种是整形或结构选项。允许一个布尔型选项,则将optval指向非零整形数;禁止一个选项optval指向一个等于零的整形数。对于布尔型选项,optlen应等于sizeof(int);对其他选项,optval指向包含所需选项的整形数或结构,而optlen则为整形数或结构的长度。SO_LINGER选项用于控制下述情况的行动:套接口上有排队的待发送数据,且 closesocket()调用已执行。参见closesocket()函数中关于SO_LINGER选项对closesocket()语义的影响。应用程序通过创建一个linger结构来设置相应的操作特性:
struct linger {
int l_onoff;
int l_linger;
};
为了允许SO_LINGER,应用程序应将l_onoff设为非零,将l_linger设为零或需要的超时值(以秒为单位),然后调用setsockopt()。为了允许SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff应设为零,然后调用setsockopt()。
缺省条件下,一个套接口不能与一个已在使用中的本地地址捆绑(参见bind())。但有时会需要“重用”地址。因为每一个连接都由本地地址和远端地址的组合唯一确定,所以只要远端地址不同,两个套接口与一个地址捆绑并无大碍。为了通知WINDOWS套接口实现不要因为一个地址已被一个套接口使用就不让它与另一个套接口捆绑,应用程序可在bind()调用前先设置SO_REUSEADDR选项。请注意仅在bind()调用时该选项才被解释;故此无需(但也无害)将一个不会共用地址的套接口设置该选项,或者在bind()对这个或其他套接口无影响情况下设置或清除这一选项。
一个应用程序可以通过打开SO_KEEPALIVE选项,使得WINDOWS套接口实现在TCP连接情况下允许使用“保持活动”包。一个WINDOWS套接口实现并不是必需支持“保持活动”,但是如果支持的话,具体的语义将与实现有关,应遵守RFC1122“Internet主机要求-通讯层”中第 4.2.3.6节的规范。如果有关连接由于“保持活动”而失效,则进行中的任何对该套接口的调用都将以WSAENETRESET错误返回,后续的任何调用将以WSAENOTCONN错误返回。
TCP_NODELAY选项禁止Nagle算法。Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。但对于某些应用来说,这种算法将降低系统性能。所以TCP_NODELAY可用来将此算法关闭。应用程序编写者只有在确切了解它的效果并确实需要的情况下,才设置TCP_NODELAY选项,因为设置后对网络性能有明显的负面影响。TCP_NODELAY是唯一使用IPPROTO_TCP层的选项,其他所有选项都使用SOL_SOCKET层。
如果设置了SO_DEBUG选项,WINDOWS套接口供应商被鼓励(但不是必需)提供输出相应的调试信息。但产生调试信息的机制以及调试信息的形式已超出本规范的讨论范围。
setsockopt()支持下列选项。其中“类型”表明optval所指数据的类型。
选项 类型 意义
SO_BROADCAST BOOL 允许套接口传送广播信息。
SO_DEBUG BOOL 记录调试信息。
SO_DONTLINER BOOL 不要因为数据未发送就阻塞关闭操作。设置本选项相当于将SO_LINGER的l_onoff元素置为零。
SO_DONTROUTE BOOL 禁止选径;直接传送。
SO_KEEPALIVE BOOL 发送“保持活动”包。
SO_LINGER struct linger FAR* 如关闭时有未发送数据,则逗留。
SO_OOBINLINE BOOL 在常规数据流中接收带外数据。
SO_RCVBUF int 为接收确定缓冲区大小。
SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind())。
SO_SNDBUF int 指定发送缓冲区大小。
TCP_NODELAY BOOL 禁止发送合并的Nagle算法。
setsockopt()不支持的BSD选项有:
选项名 类型 意义
SO_ACCEPTCONN BOOL 套接口在监听。
SO_ERROR int 获取错误状态并清除。
SO_RCVLOWAT int 接收低级水印。
SO_RCVTIMEO int 接收超时。
SO_SNDLOWAT int 发送低级水印。
SO_SNDTIMEO int 发送超时。
SO_TYPE int 套接口类型。
IP_OPTIONS 在IP头中设置选项。
返回值:
若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
错误代码:
WSANOTINITIALISED:在使用此API之前应首先成功地调用WSAStartup()。
WSAENETDOWN:WINDOWS套接口实现检测到网络子系统失效。
WSAEFAULT:optval不是进程地址空间中的一个有效部分。
WSAEINPROGRESS:一个阻塞的WINDOWS套接口调用正在运行中。
WSAEINVAL:level值非法,或optval中的信息非法。
WSAENETRESET:当SO_KEEPALIVE设置后连接超时。
WSAENOPROTOOPT:未知或不支持选项。其中,SOCK_STREAM类型的套接口不支持SO_BROADCAST选项,SOCK_DGRAM 类型的套接口不支持SO_DONTLINGER 、SO_KEEPALIVE、SO_LINGER和SO_OOBINLINE选项。
WSAENOTCONN:当设置SO_KEEPALIVE后连接被复位。
WSAENOTSOCK:描述字不是一个套接口。

⑷ 简答TCP协议的工作过程

你大概说的是3步握手吧,这跟传真机的5部握手很类似。
下面的资料希望对你有用

TCP/IP 是很多的不同的协议组成,实际上是一个协议组,TCP 用户数据报表协议(也
称作TCP 传输控制协议,Transport Control Protocol。可靠的主机到主机层协议。这里要先
强调一下,传输控制协议是OSI 网络的第四层的叫法,TCP 传输控制协议是TCP/IP 传输的
6 个基本协议的一种。两个TCP 意思非相同。)。TCP 是一种可靠的面向连接的传送服务。
它在传送数据时是分段进行的,主机交换数据必须建立一个会话。它用比特流通信,即数据
被作为无结构的字节流。通过每个TCP 传输的字段指定顺序号,以获得可靠性。是在OSI
参考模型中的第四层,TCP 是使用IP 的网间互联功能而提供可靠的数据传输,IP 不停的把
报文放到网络上,而TCP 是负责确信报文到达。在协同IP 的操作中TCP 负责:握手过程、
报文管理、流量控制、错误检测和处理(控制),可以根据一定的编号顺序对非正常顺序的
报文给予从新排列顺序。关于TCP 的RFC 文档有RFC793、RFC791、RFC1700。
在TCP 会话初期,有所谓的“三握手”:对每次发送的数据量是怎样跟踪进行协商使
数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完
毕后何时撤消联系,并建立虚连接。为了提供可靠的传送,TCP 在发送新的数据之前,以
特定的顺序将数据包的序号,并需要这些包传送给目标机之后的确认消息。TCP 总是用来
发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。由于TCP 需要
时刻跟踪,需要额外开销,使得TCP 的格式有些显得复杂。下面就让我们看一个TCP 的
经典案例,这是后来被称为MITNICK 攻击中KEVIN 开创了两种攻击技术:
TCP 会话劫持

SYN FLOOD(同步洪流)

在这里我们讨论的时TCP 会话劫持的问题。

先让我们明白TCP 建立连接的基本简单的过程。为了建设一个小型的模仿环境我们假

设有3 台接入互联网的机器。A 为攻击者操纵的攻击机。B 为中介跳板机器(受信任的服务

器)。C 为受害者使用的机器(多是服务器),这里把C 机器锁定为目标机器。A 机器向B

机器发送SYN 包,请求建立连接,这时已经响应请求的B 机器会向A 机器回应SYN/ACK

表明同意建立连接,当A 机器接受到B 机器发送的SYN/ACK 回应时,发送应答ACK 建立

A 机器与B 机器的网络连接。这样一个两台机器之间的TCP 通话信道就建立成功了。

B 终端受信任的服务器向C 机器发起TCP 连接,A 机器对服务器发起SYN 信息,使

C 机器不能响应B 机器。在同时A 机器也向B 机器发送虚假的C 机器回应的SYN 数据包,

接收到SYN 数据包的B 机器(被C 机器信任)开始发送应答连接建立的SYN/ACK 数据包,

这时C 机器正在忙于响应以前发送的SYN 数据而无暇回应B 机器,而A 机器的攻击者预

测出B 机器包的序列号(现在的TCP 序列号预测难度有所加大)假冒C 机器向B 机器发送

应答ACK 这时攻击者骗取B 机器的信任,假冒C 机器与B 机器建立起TCP 协议的对话连

接。这个时候的C 机器还是在响应攻击者A 机器发送的SYN 数据。

TCP 协议栈的弱点:TCP 连接的资源消耗,其中包括:数据包信息、条件状态、序列

号等。通过故意不完成建立连接所需要的三次握手过程,造成连接一方的资源耗尽。

通过攻击者有意的不完成建立连接所需要的三次握手的全过程,从而造成了C 机器的

资源耗尽。序列号的可预测性,目标主机应答连接请求时返回的SYN/ACK 的序列号时可预

测的。(早期TCP 协议栈,具体的可以参见1981 年出的关于TCP 雏形的RFC793 文档)

TCP 头结构

TCP 协议头最少20 个字节,包括以下的区域(由于翻译不禁相同,文章中给出

相应的英文单词):

TCP 源端口(Source Port):16 位的源端口其中包含初始化通信的端口。源端口和

源IP 地址的作用是标示报问的返回地址。

TCP 目的端口(Destination port):16 位的目的端口域定义传输的目的。这个端口指

明报文接收计算机上的应用程序地址接口。

TCP 序列号(序列码,Sequence Number):32 位的序列号由接收端计算机使用,重

新分段的报文成最初形式。当SYN 出现,序列码实际上是初始序列码(ISN),而第一个数

据字节是ISN+1。这个序列号(序列码)是可以补偿传输中的不一致。

TCP 应答号(Acknowledgment Number):32 位的序列号由接收端计算机使用,重

组分段的报文成最初形式。,如果设置了ACK 控制位,这个值表示一个准备接收的包的序

列码。

数据偏移量(HLEN):4 位包括TCP 头大小,指示何处数据开始。

保留(Reserved):6 位值域,这些位必须是0。为了将来定义新的用途所保留。

标志(Code Bits):6 位标志域。表示为:紧急标志、有意义的应答标志、推、重置

连接标志、同步序列号标志、完成发送数据标志。按照顺序排列是:URG、ACK、PSH、

RST、SYN、FIN。

窗口(Window):16 位,用来表示想收到的每个TCP 数据段的大小。

校验位(Checksum):16 位TCP 头。源机器基于数据内容计算一个数值,收信息机

要与源机器数值结果完全一样,从而证明数据的有效性。

优先指针(紧急,Urgent Pointer):16 位,指向后面是优先数据的字节,在URG

标志设置了时才有效。如果URG 标志没有被设置,紧急域作为填充。加快处理标示为紧急

的数据段。

选项(Option):长度不定,但长度必须以字节。如果没有选项就表示这个一字节

的域等于0。

填充:不定长,填充的内容必须为0,它是为了数学目的而存在。目的是确保空

间的可预测性。保证包头的结合和数据的开始处偏移量能够被32 整除,一般额外的零以保

证TCP 头是32 位的整数倍。

标志控制功能

URG:紧急标志

紧急(The urgent pointer) 标志有效。紧急标志置位,

ACK:确认标志

确认编号(Acknowledgement Number)栏有效。大多数情况下该标志位是置位的。

TCP 报头内的确认编号栏内包含的确认编号(w+1,Figure:1)为下一个预期的序列编号,同

时提示远端系统已经成功接收所有数据。

PSH:推标志

该标志置位时,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用

处理。在处理telnet 或rlogin 等交互模式的连接时,该标志总是置位的。

RST:复位标志

复位标志有效。用于复位相应的TCP 连接。

SYN:同步标志

同步序列编号(Synchronize Sequence Numbers)栏有效。该标志仅在三次握手建立

TCP 连接时有效。它提示TCP 连接的服务端检查序列编号,该序列编号为TCP 连接初始端

(一般是客户端)的初始序列编号。在这里,可以把TCP 序列编号看作是一个范围从0 到4,

294,967,295 的32 位计数器。通过TCP 连接交换的数据中每一个字节都经过序列编号。

在TCP 报头中的序列编号栏包括了TCP 分段中第一个字节的序列编号。

FIN:结束标志

带有该标志置位的数据包用来结束一个TCP 回话,但对应端口仍处于开放状态,

准备接收后续数据。

服务端处于监听状态,客户端用于建立连接请求的数据包(IP packet)按照TCP/IP

协议堆栈组合成为TCP 处理的分段(segment)。

分析报头信息: TCP 层接收到相应的TCP 和IP 报头,将这些信息存储到内存中。

检查TCP 校验和(checksum):标准的校验和位于分段之中(Figure:2)。如果检验

失败,不返回确认,该分段丢弃,并等待客户端进行重传。

查找协议控制块(PCB{}):TCP 查找与该连接相关联的协议控制块。如果没有找

到,TCP 将该分段丢弃并返回RST。(这就是TCP 处理没有端口监听情况下的机制) 如果该

协议控制块存在,但状态为关闭,服务端不调用connect()或listen()。该分段丢弃,但不返

回RST。客户端会尝试重新建立连接请求。

建立新的socket:当处于监听状态的socket 收到该分段时,会建立一个子socket,

同时还有socket{},tcpcb{}和pub{}建立。这时如果有错误发生,会通过标志位来拆除相应

的socket 和释放内存,TCP 连接失败。如果缓存队列处于填满状态,TCP 认为有错误发生,

所有的后续连接请求会被拒绝。这里可以看出SYN Flood 攻击是如何起作用的。

丢弃:如果该分段中的标志为RST 或ACK,或者没有SYN 标志,则该分段丢弃。

并释放相应的内存。

发送序列变量

SND.UNA : 发送未确认

SND.NXT : 发送下一个

SND.WND : 发送窗口

SND.UP : 发送优先指针

SND.WL1 : 用于最后窗口更新的段序列号

SND.WL2 : 用于最后窗口更新的段确认号

ISS : 初始发送序列号

接收序列号

RCV.NXT : 接收下一个

RCV.WND : 接收下一个

RCV.UP : 接收优先指针

IRS : 初始接收序列号

当前段变量

SEG.SEQ : 段序列号

SEG.ACK : 段确认标记

SEG.LEN : 段长

SEG.WND : 段窗口

SEG.UP : 段紧急指针

SEG.PRC : 段优先级

CLOSED 表示没有连接,各个状态的意义如下:

LISTEN : 监听来自远方TCP 端口的连接请求。

SYN-SENT : 在发送连接请求后等待匹配的连接请求。

SYN-RECEIVED : 在收到和发送一个连接请求后等待对连接请求的确认。

ESTABLISHED : 代表一个打开的连接,数据可以传送给用户。

FIN-WAIT-1 : 等待远程TCP 的连接中断请求,或先前的连接中断请求的确认。

FIN-WAIT-2 : 从远程TCP 等待连接中断请求。

CLOSE-WAIT : 等待从本地用户发来的连接中断请求。

CLOSING : 等待远程TCP 对连接中断的确认。

LAST-ACK : 等待原来发向远程TCP 的连接中断请求的确认。

TIME-WAIT : 等待足够的时间以确保远程TCP 接收到连接中断请求的确认。

CLOSED : 没有任何连接状态。

TCP 连接过程是状态的转换,促使发生状态转换的是用户调用:OPEN,SEND,

RECEIVE,CLOSE,ABORT 和STATUS。传送过来的数据段,特别那些包括以下标记的数

据段SYN,ACK,RST 和FIN。还有超时,上面所说的都会时TCP 状态发生变化。

序列号

请注意,我们在TCP 连接中发送的字节都有一个序列号。因为编了号,所以可以

确认它们的收到。对序列号的确认是累积性的。TCP 必须进行的序列号比较操作种类包括

以下几种:

①决定一些发送了的但未确认的序列号。

②决定所有的序列号都已经收到了。

③决定下一个段中应该包括的序列号。

对于发送的数据TCP 要接收确认,确认时必须进行的:

SND.UNA = 最老的确认了的序列号。

SND.NXT = 下一个要发送的序列号。

SEG.ACK = 接收TCP 的确认,接收TCP 期待的下一个序列号。

SEG.SEQ = 一个数据段的第一个序列号。

SEG.LEN = 数据段中包括的字节数。

SEG.SEQ+SEG.LEN-1 = 数据段的最后一个序列号。

如果一个数据段的序列号小于等于确认号的值,那么整个数据段就被确认了。而

在接收数据时下面的比较操作是必须的:

RCV.NXT = 期待的序列号和接收窗口的最低沿。

RCV.NXT+RCV.WND:1 = 最后一个序列号和接收窗口的最高沿。

SEG.SEQ = 接收到的第一个序列号。

SEG.SEQ+SEG.LEN:1 = 接收到的最后一个序列号。

⑸ tcp接收缓冲区中的数据什么时候清楚

1. 只要收到了包,就会ACK。
2. TCP在ACK的同时会带有window大小值,表示这边能接受的数据量。发送方会根据这个调整数据量。
3. 接收方缓冲区满时,回给发送方的window值就是0。
4. 发送方看到window为0的包,会启动一个定时器,隔一段时间发一个包试探。
5. 一旦接收方缓冲区有足够空间了,就会给window赋上非0值。发送方就又开始发送了。

⑹ 传输单元缓存区是什么简单的定义一下能明白就行。

TCP的接收缓冲区是用来缓存从对端接收到的数据,这些数据后续会被应用程序读取。一般情况下,TCP报文的窗口值反映接收缓冲区的空闲空间的大小。对于带宽比较大、有大批量数据的连接,增大接收缓冲区的大小可以显着提供TCP传输性能。TCP的发送缓冲区是用来缓存应用程序的数据,发送缓冲区的每个字节都有序列号,被应答确认的序列号对应的数据会从发送缓冲区删除掉。增大发送缓冲区可以提高TCP跟应用程序的交互能力,也因此会提高性能。但是增大接收和发送缓冲区会导致TCP占用比较多的内存。

⑺ 可靠传输的TCP可靠传输机制

总结一下,TCP通过下列方式来提供可靠性:
1)面向字节流和缓存机制:应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据长度将保持不变。由TCP传递给IP的信息单位称为报文段或段(segment)。
2)超时重发和确认机制:当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。当TCP收到发自TCP连接另一端的数据,它将发送一个确认。TCP有延迟确认的功能,在此功能没有打开,则是立即确认。功能打开,则由定时器触发确认时间点。
3)检验和机制:TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段(希望发端超时并重发)。
4)字节编号机制:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。
5)自动丢弃重复机制:既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。
6)流量控制:TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(byte stream service)。如果一方的应用程序先传10字节,又传20字节,再传50字节,连接的另一方将无法了解发方每次发送了多少字节。只要自己的接收缓存没有塞满,TCP 接收方将有多少就收多少。一端将字节流放到TCP连接上,同样的字节流将出现在TCP连接的另一端。
另外,TCP对字节流的内容不作任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCⅡ字符、EBCDIC字符或者其他类型数据。对字节流的解释由TCP连接双方的应用层解释。

⑻ 关于socket通信中tcp缓存的问题

不会清空的,只有在收到ack后才会清空对应的数据。如果没有收到ACK,在一个超时时间后,发送端会重新尝试发送缓存里面的数据,你网络断开以后再接上,数据依旧可以发送过去,但是如果断开时间过长,发送方已经放弃重新发送了,则再连接上也不能发送数据了。

⑼ TCP中,send一个缓冲区的数据,是否用一个recv就可接收完整

不一定的。
TCP是流式套接字,你所面对的只是一个字符流。它只能保证各个字节按顺序到达,不会乱序。至于分几次,每次几个,说不准。
总而言这,TCP不是“面向消息”的。你如果需要基于消息的机制,只能自己制定应用层的协议(比如通过长度或者特殊的信息来标记消息的开始和结束),然后自己写代码进行封装。
假如send一次,是不是会有情况要recv两次才能收全?
recv的缓冲区足够大。
recv有返回值,为每次收到长度,
你收的时候,判断一下,有没有收全,
至于几次不好说,
TCP出错的话会重发的
tcp是不分包的
所以你得循环来收
最好加个长度
int iLen=50
int curLen=0;

while((curLen=recv(...,iLen))>0){
iLen-=curLen;
if(iLen<=0)
break;
}

tcp有可能粘包,所接受端要做分包处理。upd就不用了这样做了。
tcp有可能粘包,所接受端要做分包处理。udp就不用了这样做了
假如send一次,是不是会有情况要recv两次才能收全?
recv的缓冲区足够大。
会的。
也可能两次发的一次全收到。

⑽ TCP采用哪些机制来实现可靠数据传输、流控和拥塞控制

1.采用面向连接的三次握手实现可靠对象传输。
2.使用数据窗口机制协商队列大小实现数据队列传输。
3.通过序列化应答和必要时重发数据包,TCP 为应用程序提供了可靠的传输流和虚拟连接服务。

下面是找到的长篇大论中比较好的文章:

一、TCP协议

1、TCP 通过以下方式提供可靠性:

◆ 应用程序分割为TCP认为最合适发送的数据块。由TCP传递给IP的信息单位叫做报文段。
◆ 当TCP发出一个报文段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能记时收到一个确认,它 就重发这个报文段。
◆ 当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常延迟几分之一秒。
◆ TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化如果收到报文段的检验和有差错,TCP将丢弃这个报文段和不确认收到这个报文段。
◆ 既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能失序,因此TCP报文段的到达也可能失序。如果必要,TCP将对收到的数据进行排序,将收到的数据以正确的顺序交给应用层。
◆ 既然IP数据报会发生重复,TCP连接端必须丢弃重复的数据。
◆ TCP还能提供流量控制,TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。
另外,TCP对字节流的内容不作任何解释。

2、TCP首部:
TCP数据被封装在一个IP数据报中,格式如下:
IP首部20 TCP首部20 TCP首部

TCP首部格式如下:
16位源端口号 16位目的端口号
32位序号
32位确认序号
4位首部长度 保留6位 U
R
G A
C
K P
S
H R
S
T S
Y
N F
I
N 16位窗口大小
16位检验和 16位紧急指针
选项
数据

说明:
(1)每个TCP段都包括源端和目的端的端口号,用于寻找发送端和接收端的应用进程。这两个值加上IP首部的源端IP地址和目的端IP地址唯一确定一个TCP连接。
(2)序号用来标识从TCP发送端向接收端发送的数据字节流,它表示在这个报文段中的第一个数据字节。如果将字节流看作在两个应用程序间的单向流动,则TCP用序号对每个字节进行计数。
(3)当建立一个新连接时,SYN标志变1。序号字段包含由这个主机选择的该连接的初始序号ISN,该主机要发送数据的第一个字节的序号为这个ISN加1,因为SYN标志使用了一个序号。
(4)既然每个被传输的字节都被计数,确认序号包含发送确认的一端所期望收到的下一个序号。因此,确认序号应当时上次已成功收到数据字节序号加1。只有ACK标志为1时确认序号字段才有效。
(5)发送ACK无需任何代价,因为32位的确认序号字段和ACK标志一样,总是TCP首部的一部分。因此一旦一个连接建立起来,这个字段总是被设置,ACK标志也总是被设置为1。
(6)TCP为应用层提供全双工的服务。因此,连接的每一端必须保持每个方向上的传输数据序号。
(7)TCP可以表述为一个没有选择确认或否认的华东窗口协议。因此TCP首部中的确认序号表示发送方已成功收到字节,但还不包含确认序号所指的字节。当前还无法对数据流中选定的部分进行确认。
(8)首部长度需要设置,因为任选字段的长度是可变的。TCP首部最多60个字节。
(9)6个标志位中的多个可同时设置为1
◆ URG-紧急指针有效
◆ ACK-确认序号有效
◆ PSH-接收方应尽快将这个报文段交给应用层
◆ RST-重建连接
◆ SYN-同步序号用来发起一个连接
◆ FIN-发送端完成发送任务
(10)TCP的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端期望接收的字节数。窗口大小是一个16为的字段,因而窗口大小最大为65535字节。
(11)检验和覆盖整个TCP报文端:TCP首部和TCP数据。这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证。TCP检验和的计算和UDP首部检验和的计算一样,也使用伪首部。
(12)紧急指针是一个正的偏移量,黄蓉序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式。
(13)最常见的可选字段是最长报文大小MMS,每个连接方通常都在通信的第一个报文段中指明这个选项。它指明本端所能接收的最大长度的报文段。

二、TCP连接的建立和终止

1、建立连接协议
(1) 请求端发送一个SYN段指明客户打算连接的服务器的端口,隐疾初始序号(ISN),这个SYN报文段为报文段1。
(2) 服务器端发回包含服务器的初始序号的SYN报文段(报文段2)作为应答。同时将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。
(3) 客户必须将确认序号设置为服务器的ISN加1以对服务器的SYN报文段进行确认(报文段3)。
这3个报文段完成连接的建立,称为三次握手。发送第一个SYN的一端将执行主动打开,接收这个SYN并发回下一个SYN的另一端执行被动打开。

2、连接终止协议
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个FIN来终止这个方向的连接。收到一个FIN只意味着这一方向上没有数据流动,一个TCP连接在收到一个FIN后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
(1) TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送(报文段4)。
(2) 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3) 服务器关闭客户端的连接,发送一个FIN给客户端(报文段6)。
(4) 客户段发回确认,并将确认序号设置为收到序号加1(报文段7)。

3、连接建立的超时
如果与服务器无法建立连接,客户端就会三次向服务器发送连接请求。在规定的时间内服务器未应答,则连接失败。

4、最大报文段长度MSS
最大报文段长度表示TCP传往另一端的最大块数据的长度。当一个连接建立时,连接的双方都要通告各自的MSS。
一般,如果没有分段发生,MSS还是越大越好。报文段越大允许每个报文段传送的数据越多,相对IP和TCP首部有更高的网络利用率。当TCP发送一个 SYN时,它能将MSS值设置为外出接口的MTU长度减去IP首部和TCP首部长度。对于以太网,MSS值可达1460。
如果目的地址为非本地的,MSS值通常默认为536,是否本地主要通过网络号区分。MSS让主机限制另一端发送数据报的长度,加上主机也能控制它发送数据报的长度,这将使以较小MTU连接到一个网络上的主机避免分段。

5、 TCP的半关闭
TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力,这就是TCP的半关闭。
客户端发送FIN,另一端发送对这个FIN的ACK报文段。当收到半关闭的一端在完成它的数据传送后,才发送FIN关闭这个方向的连接,客户端再对这个FIN确认,这个连接才彻底关闭。

6、2MSL连接
TIME_WAIT状态也称为2MSL等待状态。每个TCP必须选择一个报文段最大生存时间(MSL)。它是任何报文段被丢弃前在网络的最长时间。
处理原则:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2MSL。这样可以让TCP再次发送最后的ACK以避免这个ACK丢失(另一端超时并重发最后的FIN)。这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口不能被使用。

7、平静时间
TCP在重启的MSL秒内不能建立任何连接,这就是平静时间。
8、FIN_WAIT_2状态
在FIN_WAIT_2状态我们已经发出了FIN,并且另一端也对它进行了确认。只有另一端的进程完成了这个关闭,我们这端才会从 FIN_WAIT_2状态进入TIME_WAIT状态。这意味着我们这端可能永远保持这个状态,另一端也将处于CLOSE_WAIT状态,并一直保持这个状态直到应用层决定进行关闭。
9、复位报文段
TCP首部的RST位是用于复位的。一般,无论合适一个报文端发往相关的连接出现错误,TCP都会发出一个复位报文段。主要情况:
(1)到不存在的端口的连接请求;
(2)异常终止一个连接。

10、同时打开
为了处理同时打开,对于同时打开它仅建立一条连接而不是两条连接。两端几乎在同时发送SYN,并进入SYN_SENT状态。当每一端收到SYN时,状态变为SYN_RCVD,同时他们都再发SYN并对收到的SYN进行确认。当双方都收到SYN及相应的ACK时,状态都变为ESTABLISHED。一个同时打开的连接需要交换4个报文段,比正常的三次握手多了一次。

11、 同时关闭
当应用层发出关闭命令,两端均从ESTABLISHED变为FIN_WAIT_1。这将导致双方各发送一个FIN,两个FIN经过网络传送后分别到达另一端。收到FIN后,状态由FIN_WAIT_1变为CLOSING,并发送最后的ACK。当收到最后的ACK,状态变为TIME_WAIT。同时关闭和正常关闭的段减缓数目相同。

12、TCP选项
每个选项的开始是1字节的kind字段,说明选项的类型。

Kind=1:选项表结束(1字节) Kind=1:无操作(1字节) Kind=2:最大报文段长度(4字节) Kind=3:窗口扩大因子(4字节) Kind=8:时间戳(10字节)
三、TCP的超时和重传

对于每个TCP连接,TCP管理4个不同的定时器。
(1) 重传定时器用于当希望收到另一端的确认。
(2) 坚持定时器使窗口大小信息保持不断流动,即使另一端关闭了其接收窗口。
(3) 保活定时器可检测到一个空闲连接的另一端何时崩溃或重启。
(4) 2MSL定时器测量一个连接处于TIME_WAIT状态的时间。

1、往返时间测量
TCP超时和重传重最重要的就是对一个给定连接的往返时间(RTT)的测量。由于路由器和网络流量均会变化,因此TCP应该跟踪这些变化并相应地改变超时时间。首先TCP必须测量在发送一个带有特别序号地字节和接收到包含该字节地确认之间的RTT。

2、拥塞避免算法
该算法假定由于分组收到损坏引起的丢失是非常少的,因此分组丢失就意味着在源主机和目的主机之间的某处网络上发生了阻塞。有两种分组丢失的指示:发生超时和收到重复的确认。拥塞避免算法需要对每个连接维持两个变量:一个拥塞窗口cwnd和一个慢启动门限ssthresh。
(1) 对一个给定的连接,初始化cwnd为1个报文段,ssthresh为65535个字节。
(2) TCP输出例程的输出不能超过cwnd和接收方通告窗口的大小。拥塞避免是发送方使用的流量控制。前者是发送方感受到的网络拥塞的估计,而后者则与接收方在该连接上的可用缓存大小有关。
(3) 当拥塞发生时,ssthresh被设置为当前窗口大小的一般(cwnd和接收方通告窗口大小的最小值,但最小为2个报文段)。此外,如果是超时引起了拥塞,则cwnd被设置为1个报文段。
(4) 当新的数据被对方确认时,就增加cwnd,但增加的方法依赖与是否正在进行慢启动或拥塞避免。如果cwnd小于或等于ssthresh,则正在进行慢启动,否则正在进行拥塞避免。

3、快速重传和快速恢复算法
如果我们一连串收到3个或以上的重复ACK,就非常可能是一个报文段丢失了。于是我们就重传丢失的数据报文段,而无需等待超时定时器溢出。
(1) 当收到第3个重复的ACK时,将ssthresh设置为当前拥塞窗口cwnd的一半,重传丢失的报文段,设置cwnd为ssthresh加上3倍的报文段大小。
(2) 每次收到另一个重复的ACK时,cwnd增加1个报文段大小并发送一个1个分组,如果允许的话。
(3)当下一个确认新数据的ACK到达时,设置cwnd为ssthresh,这个ACK应该时在进行重传后的一个往返时间内对步骤1重重传的确认。另外,这个 ACK也应该是对丢失的分组和收到的第一个重复的ACK之间的所有中间报文段的确认。

4、 ICMP差错
TCP如何处理一个给定的连接返回的ICMP差错。TCP能够遇到的最常见的ICMP差错就是源站抑制、主机不可达和网络不可达。
(1) 一个接收到的源站抑制引起拥塞窗口cwnd被置为1个报文段大小来发起慢启动,但是慢启动门限ssthresh没有变化,所以窗口将打开直到它开放了所有的通路或者发生了拥塞。
(2) 一个接收到的主机不可达或网络不可达实际都被忽略,因为这两个差错都被认为是短暂现象。TCP试图发送引起该差错的数据,尽管最终有可能会超时。

5、重新分组:
当TCP超时并重传时,它并不一定要重传同样的报文段,相反,TCP允许进行重新分组而发送一个较大的报文段。这是允许的,因为TCP是使用字节序号而不是报文段序号来进行识别它所要发送的数据和进行确认。

四、TCP的坚持定时器

ACK的传输并不可靠,也就是说,TCP不对ACK报文段进行确认,TCP只确认那些包含数据的ACK报文段。为了防止因为ACK报文段丢失而双方进行等待的问题,发送方用一个坚持定时器来周期性地向接收方查询。这些从发送方发出地报文段称为窗口探查。

五、TCP的保活定时器
如果一个给定的连接在2小时内没有任何动作,那么服务器就向客户发送一个探查报文段。客户主机必须处于以下4个状态之一。
(1) 客户主机依然正常运行,并从服务器可达。客户的TCP响应正常,而服务器也知道对方的正常工作的。服务器在2小时内将保活定时器复位。
(2) 客户主机已经崩溃,并且关闭或者正在重新启动。在任何一种情况下,客户的TCP都没有响应。服务器将不能收到对探查的响应,并在75秒后超时。总共发送10个探查,间隔75秒。
(3) 客户主机崩溃并已经重新启动。这是服务器将收到一个对其保活探查的响应,但这个响应是一个复位,使得服务器终止这个连接。
(4) 客户主机正常运行,但是从服务器不可达。

六、TCP的一些性能

1、 路径MTU发现:
TCP的路径MTU发现按如下方式进行:在连接建立时,TCP使用输出接口或对段声明的MSS中的最下MTU作为其实的报文段大小。路径MTU发现不允许TCP超过对端声明的MSS。如果对端没有指定一个MSS,则默认为536。
一旦选定了起始的报文段大小,在该连接上的所有被TCP发送的IP数据报都将被设置DF位。如果中间路由器需要对一个设置了DF标志的数据报进行分片,它就丢弃这个数据报,并产生一个ICMP的“不能分片”差错。
如果收到这个ICMP差错,TCP就减少段大小并进行重传。如果路由器产生的是一个较新的该类ICMP差错,则报文段大小被设置位下一跳的MTU减去 IP和TCP的首部长度。如果是一个较旧的该类ICMP差错,则必须尝试下一个可能的最小MTU。

2、 长肥管道
一个连接的容量=带宽X时延(RTT)。具有大的带宽时延乘积的网络称为长肥网络(LFN)。一个运行在LFN的TCP连接称为长肥管道。管道可以被水平拉长(一个长的RTT),或被垂直拉高(较高的带宽),或两个方向拉伸。

3、窗口扩大选项:
窗口扩大选项使TCP的窗口定义从16位增加到32位,这并不是通过修改TCP首部来实现的,TCP首部仍然使用16位,而是通过定义一个选项实现对16位的扩大操作来完成的。

4、时间戳选项:
时间戳选项使发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT。