TCP协议如何保证数据可靠性
为什么TCP协议是可靠的?TCP协议是怎么保证数据的可靠的?答:能够保证TCP协议可靠的算法有检验和,连接管理机制,ACK应答机制,快速重传和超时重传机制,滑动窗口机制,拥塞控制机制,这些机制共同保证TCP协议的可靠性。检验和:TCP检验和的计算与UDP一样,在计算时要加上12byte的伪首部,检验范围包括TCP首部及数据部分,但是UDP的检验和字段为可选的,而TCP中是必须有的。计算方法为:在发送方将整个报文段分为多个16位的段,然后将所有段进行反码相加,将结果存放在检验和字段中,接收方用相同的方法进行计算,如最终结果为检验字段所有位是全1则正确(UDP中为0是正确),否则存在错误。可以保证接收方能判断当前报文是否属于自己要接受的报文,如果为0,那就是,不为0,则不是,丢弃此报文。抽象些来说就像是取快递,你的电话姓名和快递上的信息一致,你才能确定这是你的快递,才会去取,不会错拿别人的快递。序列号:TCP 对每个报文进行编号,这些编号就是序列号。而序列号有多种作用a:保证可靠性,当接收到的数据失序时,就能立马知道b:去除重复的报文,数据传输过程中的确认应答,重发控制,重复控制等功能都要依靠序列号来实先。c:提高效率,可以实现多次发送,一次确认。ACK应答机制:发送的每一条消息,都需要对方发送一条消息来回复消息是否被收到。主要实现是TCP的首部来控制,当ACK =1 时ack才有效,ack等于期望下一个传输过来的序号,也就是上一次接收消息的序号+1。这样就可以保证消息能被确认接收。(三次握手和四次挥手都在用这个机制)连接管理机制:三次握手建立连接与四次挥手断开连接,保证了TCP的全双工工作。快重传和超时重传:保证了数据能够不丢失的传输数据。(注意:超时重传机制和快重传机制,同时存在。谁先检验到报文失序,谁就生效。)滑动窗口:滑动窗口既提高了报文传输的效率,也避免了发送方发送过多的数据而导致接收方无法正常处理的异常。数据的发送方和接收方都有滑动窗口,对于发送方来说,窗口内就是可以发送的报文,当窗口的前沿紧挨的报文发送并且确认时,窗口向后移动。而窗口的后沿可以向前移动,当接收方处理不了那么多的报文时,就会发送消息告诉发送方,此时滑动窗口就需要缩小,所以后沿前移。但是TCP非常不建议窗口后沿前移。说到滑动窗口,就不得不梳理一下消息发送的过程中的缓存机制:发送方和接收方的滑动窗口工作流程:伴随着效率的提升,也会有问题产生,如果消息没被确认怎么办如图所示,假如31,32,33,34,报文发送了,32,33,34都被确认了,31没被确认怎么办呢?这时就重新发送31,并且31之后的数据报全部重新发送。在图中我们还会发现窗口的前沿和后沿会移动,窗口前沿和后沿都向后移动,意味着前沿紧挨的报文发送并被确认,而后沿的前移意味着,接收端处理那么多消息,请缩小窗口的大小。所以解决了发送的数据过多,导致接收端无法正常接收的异常。拥塞控制:拥塞控制使得宏观网络中的资源能够合理的应用。实现的算法有四个,慢开始,拥塞避免,快速回复,和快速重传.1.慢开始指一开始发送报文时,不清楚网络中的情况,试探性的发送1cwnd(拥塞窗口)的数据量。2.如果没有到ssthresh(慢开始门限值),则以指数形式增长,一直到门限值;3.当到达门限值时,此时采用拥塞避免算法让拥塞窗口缓慢增长,即每经过一个RTT(往返时间)就把发送方的拥塞窗口+1,不能是指数性增长了,一直到发生网络拥塞为止。4.当发生网络拥塞时,把ssthresh的值设置为出现拥塞时发送窗口大小的一半,然后把拥塞窗口设置为1,再次执行慢开始算法。5.在发送方知道只是丢失了个别的报文段时,采用快恢复算法,将门限值设置成拥塞窗口大小的一半,并将拥塞窗口设置为当前门限值,并执行拥塞避免算法。6.当发送方一连收到3个对同一个报文段的重复确认时,采用快速重传算法,立即进行重传,这样就不会出现超时,可以使整个网络的吞吐量提高约20%。

tcp协议可靠吗
TCP IP协议是互联网传输的基本协议,还是非常可靠的。

一个有关问题,TCP是绝对100%可靠的吗
在多线程任务中,TCP任务通过三次握手能建立可靠的连接,但是经常会发生在数据传输或通信时发生网络突然断开或者长时间连接空循环监听而未进行操作,需要在软件设计时考虑程序运行中检测到服务器对客户端的这一“虚连接”现象。 如果主机崩溃,write是否阻塞取决于内核的tcp缓冲区,但read将一直阻塞,直到超时ETIMEOUT,或由于某些中间路由器的原因返回EHOSTUNREACH/ENETUNREACH。select不能检测到该情况。如果主机崩溃并重起,客户的write到达主机时主机响应RST,客户的read将返ECONNRESET。此处的”非正常断开”指TCP连接不是以优雅的方式断开,如网线故障等物理链路的原因,还有突然主机断电等原因。心跳机制有两种方法可以检测:1.TCP连接双方定时发握手消息2.利用TCP协议栈中的KeepAlive探测第二种方法简单可靠,只需对TCP连接两个Socket设定KeepAlive探测,所以本文只讲第二种方法在Linux,Window2000下的实现(在其它的平台上没有作进一步的测试)1)Windows平台C代码//定义结构及宏struct TCP_KEEPALIVE {u_longonoff;u_longkeepalivetime;u_longkeepaliveinterval;} ;#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)//KeepAlive实现TCP_KEEPALIVE inKeepAlive = {0}; //输入参数unsigned long ulInLen = sizeof(TCP_KEEPALIVE);TCP_KEEPALIVE outKeepAlive = {0}; //输出参数unsigned long ulOutLen = sizeof(TCP_KEEPALIVE);unsigned long ulBytesReturn = 0;//设置socket的keep alive为5秒,并且发送次数为3次inKeepAlive.onoff = 1;inKeepAlive.keepaliveinterval = 5000; //两次KeepAlive探测间的时间间隔inKeepAlive.keepalivetime = 5000; //开始首次KeepAlive探测前的TCP空闭时间if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS,(LPVOID)&inKeepAlive, ulInLen,(LPVOID)&outKeepAlive, ulOutLen,&ulBytesReturn, NULL, NULL) == SOCKET_ERROR){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) WSAIoctl failed. error code(%d)!n"), WSAGetLastError()));}//定义结构及宏 struct TCP_KEEPALIVE { u_longonoff; u_longkeepalivetime; u_longkeepaliveinterval; } ; #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) //KeepAlive实现 TCP_KEEPALIVE inKeepAlive = {0}; //输入参数 unsigned long ulInLen = sizeof(TCP_KEEPALIVE); TCP_KEEPALIVE outKeepAlive = {0}; //输出参数 unsigned long ulOutLen = sizeof(TCP_KEEPALIVE); unsigned long ulBytesReturn = 0; //设置socket的keep alive为5秒,并且发送次数为3次 inKeepAlive.onoff = 1; inKeepAlive.keepaliveinterval = 5000; //两次KeepAlive探测间的时间间隔 inKeepAlive.keepalivetime = 5000; //开始首次KeepAlive探测前的TCP空闭时间 if (WSAIoctl((unsigned int)s, SIO_KEEPALIVE_VALS, (LPVOID)&inKeepAlive, ulInLen, (LPVOID)&outKeepAlive, ulOutLen, &ulBytesReturn, NULL, NULL) == SOCKET_ERROR) { ACE_DEBUG ((LM_INFO, ACE_TEXT ("(%P|%t) WSAIoctl failed. error code(%d)!n"), WSAGetLastError())); }2)Linux平台C代码#include……////KeepAlive实现//下面代码要求有ACE,如果没有包含ACE,则请把用到的ACE函数改成linux相应的接口int keepAlive = 1;//设定KeepAliveint keepIdle = 5;//开始首次KeepAlive探测前的TCP空闭时间int keepInterval = 5;//两次KeepAlive探测间的时间间隔int keepCount = 3;//判定断开前的KeepAlive探测次数if(setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(void*)&keepAlive,sizeof(keepAlive)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt SO_KEEPALIVE error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPIDLE,(void *)&keepIdle,sizeof(keepIdle)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPIDLE error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPINTVL,(void *)&keepInterval,sizeof(keepInterval)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t) setsockopt TCP_KEEPINTVL error!n")));}if(setsockopt(s,SOL_TCP,TCP_KEEPCNT,(void *)&keepCount,sizeof(keepCount)) == -1){ACE_DEBUG ((LM_INFO,ACE_TEXT ("(%P|%t)setsockopt TCP_KEEPCNT error!n")));}心跳机制:定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性。网络中的接收和发送数据都是使用WINDOWS中的SOCKET进行实现。但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题。可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机制。其实TCP中已经为我们实现了一个叫做心跳的机制。如果你设置了心跳,那TCP就会在一定的时间(比如你设置的是3秒钟)内发送你设置的次数的心跳(比如说2次),并且此信息不会影响你自己定义的协议。所谓“心跳”就是定时发送一个自定义的结构体(心跳包或心跳帧),让对方知道自己“在线”。以确保链接的有效性。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理。一般是客户端。服务器也可以定时轮询发心跳下去。心跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项。系统默认是设置的是2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。心跳包一般来说都是在逻辑层发送空的包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀当然,这个自然是要由逻辑层根据需求去做了。总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。TCP连接异常断开后操作系统会告诉你,你查询套接字的状态会得到异常,或者当发现函数失败WSAGetLastError的时候也会得到内核的通知。// 发送回应消息int nSend = Send4IntMsg(sock, (char*)(LPCTSTR)strSendBuf,strSendBuf.GetLength(), errMsg);if (nSend < 0) //发送消息失败closesocket(sock);//重新连接 在B/S编程和UDP编程时才用到心跳。比如定期向web服务器发一个request证明自己在线。http协议是请求一下就断开了,每次都要重新连接,重新请求,这种情况下才有必要用心跳机制。一般的TCP通信都是长连接,不可能频繁连接和断开。对于长期保持连接的情况,一旦断开,操作系统底层都会通知你,你需要解决的是如何获取到系统的通知。

为什么说TCP是面向连接的.可靠的.可控制流量的?
TCP协议提供的是可靠的、面向连接的传输控制协议,即在传输数据前要先建立逻辑连接,然后再传输数据,最后释放连接3个过程。TCP提供端到端、全双工通信;采用字节流方式,如果字节流太长,将其分段;提供紧急数据传送功能。TCP提供一种面向连接的、可靠的字节流服务。 面向连接意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。这一过程与打电话很相似,先拨号振铃,等待对方摘机说“喂”,然后才说明是谁。

TCP是如何实现可靠传输的?
在计算机网络的经典五层协议中,TCP属于运输层,实现了进程间的通信,保证了数据的可靠传输,属于计算机网络协议族中最重要的协议之一,那么TCP是如何实现可靠数据传输的呢?运输层的进程间通信是通过socket实现的,socket是一个抽象的概念,在Linux系统中以文件的形式存在。网络层通过IP来区分主机,运输层则增加了端口的概念来区分进程。TCP协议中使用目标IP、目标端口、源IP、源端口来定义一个socket,只需要在运输层的报文头部附加上这些信息,目标主机就会知道数据要发送那个socket,对应监听该socket的进程就可以收到数据进行处理。TCP报文包括首部和数据部分,首部附加了TCP报文的信息,首部长度固定部分为20字节,还有40字节的可选部分,具体如下图所示:其中几个关键字段的作用如下:网络层只管尽可能将数据从一个主机发送到另一个主机,并不保证数据可靠到达,由于网络环境总是不稳定的,可能存在丢包、差错等请求,TCP则通过一系列的机制在运输层保证了数据的可靠传输。网络传输可能发生的异常情况和解决方法:要实现可靠传输,最简单的方法就是发送方发送一个报文,接收方收到报文后发送确认报文表示我收到了,你可以发下一个了,传输模型如下:这种方式保证可靠传输称为停止等待协议,这种方式缺点也很明显,效率非常低。为了提高传输效率,充分利用带宽,发送方会连续的发送数据包,如下图所示:客户端不等收到前一个包的确认报文就开始不断的发下一个包,这样可以充分利用网络带宽,提高传输效率,但是于此同时也带来了另外的问题,那么TCP是如何解决这些问题的?累计确认:网络中充斥着大量的发送包和确认回复报文,这些数据只是为了确认报文到达,并不是实际需要传输的数据。是不是一定要每一个报文都要发一个回复确认的报文呢,TCP采用了累计确认的方法:接收方在累计收到了一定量的数据包后发送一个确认报文告诉发送方在此之前的数据包都已经收到了,这样便可以减少确认报文的数量,提高带宽利用率。GBN(回退n步):如果发生丢包的情况,在连续ARQ中,如果接受方收到了123 567个字节,编号为4字节的包丢失了,按照累计确认只能发送3的确认回复,567都要丢掉,因为发送发会进行重传。选择确认ACK:在TCP报文头部的选项字段部分设置已收到的报文,每一段用两个边界来确定,比如上述情况可以用[1,3]和[5,7]来表示,客户端就会根据选项只重传丢失的数据段。因为接收方读数据的能力有限,发送发不能一直发送报文直到把缓冲区所有数据发送完,这样会导致接收方无法接收丢弃掉数据包,发送方收不到确认认为超时又会继续重传,产生了大量无用数据的重传。对此情况TCP使用滑动窗口来解决,基本模型如下:滑动窗口机制实现了TCP的流量控制,不至于发送太快导致太多的数据丢弃和重传。为了避免网络过分拥挤导致丢包严重,传输效率低,TCP实现了拥塞控制机制,拥塞控制的解决办法本质上是流量控制,控制发送方发送的速度,而上文提到流量控制是通过滑动窗口来实现的,所以最终也是通过调整发送方的滑动窗口大小来实现的。拥塞控制的几个重要的概念:慢启动、拥塞避免、快恢复、快重传Reno算法是比较常见的TCP实现的拥塞控制算法,其他拥塞算法还有Tahoe(已废弃不用)、New Reno等,通过拥塞控制算法可以很大程度避免网络拥挤。【书籍】计算机网络:自顶向下方法【码农有道】 这一篇TCP总结请收下

本文由 在线网速测试 整理编辑,转载请注明出处。