目录
网络边缘的节点才有运输层,网络中间的节点没有传输层。
16位端口号:
熟知端口号:0-1023 FTP 21 Talent 23 SMTP 25 Http 80
登记端口号:数值为1024~49151,为没有熟知端口号的应用程序使用的。使用这个范围的端口号必须在 IANA 登记,以防止重复
客户端口号:数值为49152~65535,留给客户进程选择暂时使用。
TCP的特点:
面向连接,面向字节流服务,可靠传输。
面向连接:通信之前必须进行连接,双方都要分配一定的内核资源。
TCP面向字节流:
面向字节流的TCP,应用程序执行多次写操作,TCP模块先将这些数据放在发送缓冲区,然后真正进行发送的时候则封装成一个或多个TCP报文,因此发送的次数和应用程序写的次数不一样,接收端同理。
面向数据报服务的UDP则不然,发送端每执行一次写操作就会发送一个UDP数据报,接收端同理,接收一个数据报则应用程序读一次。
TCP报文首部
复位报文段:特殊情况下,发送复位报文段,通知对端关闭连接或者重建连接。
访问不存在的端口:若对端访问不存在的端口则,发送RST,如在TIME_WAIT状态下重新进行连接则会发送RST。
异常终止连接:给发送方发送一个RST报文,发送方异常终止,所有发送队列的数据都会丢弃。
处理半打开连接:S一端发送结束报文,或异常终止,而对端C没有接收到终止报文,则处于半打开状态。若C发送数据则S发送RST告知其重新连接。
TCP C/S模型过程:
send函数用来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答,send的作用是将要发送的数据拷贝到缓冲区,协议负责传输。
recv函数用来从TCP连接的另一端接收数据,当应用程序调用recv函数时,recv先等待s的发送缓冲中的数据被协议传送完毕,然后从缓冲区中读取接收到的内容给应用层。
accept函数用了接收一个连接,内核维护了半连接队列和一个已完成连接队列,当队列为空的时候,accept函数阻塞,不为空的时候accept函数从上边取下来一个已完成连接,返回一个文件描述符。
结束阶段:C端同时发送FIN则进入CLOSING状态,收到ACK则直接进入TIME_WAIT
C端发送FIN后收到S端的FIN和ACK直接进入TIME_WAIT
S端经历CLOSE_WAIT状态,LASK_ACK状态。
TIME_WAIT 2MSL:
1,确保最后一个确认报文段能够到达。如果 B 没收到 A 发送来的确认报文段,那么就会重新发送连接释放请求报文段,A 等待一段时间就是为了处理这种情况的发生。
2,防止“已失效的连接请求报文段”,防止串话。(若不等,则可能在2MSL期间在建立同一条链接,前面老的链接未完全消逝,剩余分组会混合在新的链接,串话,在TIME_WAIT状态无法发起链接,2MSL后要么重新发送请求释放(1),要么链接关闭,分组消逝,此时可以重新发起新链接)
TCP可靠传输手段:
接收方一般采用累积确认的方式。即不必对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了。
TCP 连接的每一端都设有两个窗口:一个发送窗口和一个接收窗口。 窗口的单位不是报文段而是字节数
2、用字节的序号进行控制。TCP 所有的确认都是基于字节序号而不是基于报文段序号
3、数据校验
4、数据合理分片和排序:
UDP:IP数据报大于1500字节,大于MTU.这个时候发送方IP层就需要分片(fragmentation).把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组.这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便无法重组数据报.将导致丢弃整个UDP数据报.
tcp会按MTU合理分片,接收方会缓存未按序到达的数据,重新排序后再交给应用层。
5、流量控制:当接收方来不及处理发送方的数据,通过滑窗机制进行流控(发送接收窗不一定一样,有时间延迟)。
5、拥塞控制:当网络拥塞时,减少数据的发送。
TCP特点: 面向字节流、面向链接、点对点、可靠、全双工
滑窗机制ARQ
发送缓存:准备发送的数据;已发送但尚未收到确认的数据。
接收缓存:按序到达的、但尚未被接收应用程序读取的数据;不按序到达的数据。
往返时延:平均加权往返时延 新的 RTTS = (1 - a) ´ (旧的 RTTS) + a ´ (新的 RTT 样本)
超时重传(RunTimeOver): RTO 应略大于上面得出的加权平均往返时间 RTTS
超时重传:
出现这些异常会触发超时重传,TCP对每个发送报文都会有一个计时器,计时器时间耗尽没有收到对应的ACK则进行超时重传。
自适应设置计时器,RTO RTT
拥塞控制
拥塞控制就是防止过多的数据注入网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制是一个全局性的过程,和流量控制不同,流量控制指点对点通信量的控制。
流量控制让发送速率不要过快,让接收方来得及接收。利用滑动窗口机制就可以实施流量控制。原理这就是运用TCP报文段中的窗口大小字段来控制,发送方的发送窗口不可以大于接收方发回的窗口大小。
拥塞窗取决于网络拥塞程度,流控窗口取决于接收端接收能力,发送段窗口取min[rwnd,cwnd]
“拥塞避免”并非完全能避免了拥塞。慢开始阶段,指数增加在拥塞避免阶段把拥塞窗口控制为按线性规律增长,每经过一个往返时间RTT ,cwnd加1,使网络比较不容易出现拥塞。不可能完全避免。
发送端怎么判断是否拥塞:
传输超时:采用慢启动算法,和拥塞避免算法。
接收到重复确认报文:采用快重传和快恢复算法。
快重传:要求接收方在收到一个失序的报文段后就立即发出重复确认,比如接收到乱序片段9的时候,接收方需要回复ACK。回复号为8 (7+1)。此后接收方如果继续收到乱序片段(序号不是8的片段),将再次重复发送ACK=8。不要等到自己发送数据时捎带确认。快重传算法规定,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
快恢复:当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh慢开始门限减半。但是接下去并不执行慢开始算法。考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,所以发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法
网络刚开始和网络超时的时候会慢启动
Keepalive和HeartBeat:
TCP长连接中可能出现的问题
1. 很多防火墙路由器等对于空闲socket自动关闭。
2. 在长连接下,对于非正常断开, 服务器并不能检测到,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。为了回收资源, 必须提供一种检测机制,于是,就有了心跳(HeartBeat)机制。
心跳机制的两种实现方案
目前而言,有两种方式实现TCP的保活(业内现状是IM方面几乎都采用第一种)
1. 应用层协议自己实现的心跳机制
很多应用层协议都有HeartBeat机制,由应用自己实现的应用层的心跳, 为心跳消息额外定义一个消息类型。通常是客户端每隔一小段时间向服务器发送一个数据包,通知服务器自己仍然在线,并传输一些可能必要的数据。使用心跳包的典型协议是IM,比如QQ/MSN/飞信等协议。
2. TCP协议支持的心跳机制Keepalive,一般实现在服务器侧,客户端被动相应。
TCP Keepalive
在TCP的机制里面,本身是存在有心跳包的机制的,TCP的选项:SO_KEEPALIVE。keepalive 来判断异常断开的原理,其实 keepalive 的原理就是 TCP 内嵌的一个心跳包。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
以服务器端为例,如果当前 server 端检测到超过一定时间(2 个小时)没有数据传输,那么会 向client 端发送一个 keep-alive packet (该 keep-alive packet 就是 ACK 和当前 TCP 序列号减一的组合),此时 client 端应该为以下三种情况之一:
1. client 端仍然存在,网络连接状况良好。此时 client 端会返回一个 ACK 。 server 端接收到 ACK 后重置计时器,在2 小时后再发送探测。如果 2 小时内连接上有数据传输,那么在该时间基础上向后推延 2 个小时。
2. 客户端异常关闭,或是网络断开。在这两种情况下, client 端都不会响应。服务器没有收到对其发出探测的响应,并且在一定时间(系统默认为 1000 ms )后重复发送 keep-alive packet ,并且重复发送一定次数。
3. 客户端曾经崩溃,但已经重启。这种情况下,服务器将会收到对其存活探测的响应,但该响应是一个复位,从而引起服务器对连接的终止。
在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
打开TCP协议已有的SO_KEEPALIVE选项. 一般实现在服务器侧,客户端被动响应。
比较:
1. TCP协议的Keepalive
优点:
系统内核完全替上层应用自动给做好了,内核层面计时器相比上层应用,更为高效
上层应用只需要处理数据收发、连接异常通知即可。使用起来简单, 减少了应用层代码的复杂度. 也会更节省流量, 因为应用层的数据传输到TCP协议层时都会被加上额外的包头包尾. 由TCP协议提供的检活, 其发的探测包, 理论上实现的会更精妙, 耗费更少的流量.。
缺点:
第一点,keepAlive只能检测连接存活,而不能检测连接可用,比如某台服务器因为某些原因导致负载超高,CPU满了,无法响应任何业务请求,但是使用 TCP 探针则仍旧能够确定连接状态,这就是典型的连接活着但业务提供方已死的状态,对客户端而言,这时的最好选择就是断线后重新连接其他服务器,而不是一直认为当前服务器是可用状态,一直向当前服务器发送些必然会失败的请求;
第二点,如果tcp连接的另一端突然掉线,这个时候我们并不知道网络已经关闭。而此时,如果有发送数据失败,tcp会自动进行重传。重传包的优先级高于keepalive的包,那就意味着,我们的keepalive总是不能发送出去。 而此时,我们也并不知道该连接已经出错而中断。在较长时间的重传失败之后,我们才会知道。
2. 应用层HeartBeat
优点:
有着更大的灵活性,可以控制检测时机,间隔和处理流程,甚至可以在心跳包上附带额外信息,最重要的是可以做到没有上面所说的缺点,不光可以检测连接存在,还可以检测连接可用。
通用, 应用层的心跳不依赖协议. 如果有一天不用TCP要改为UDP了, 协议层不提供心跳机制了, 但是你应用层的心跳依旧是通用的, 可能只需要做少许改动就可以继续使用。
缺点:
需要自己实现,增加开发工作量,由于应用特定的网络框架,还可能增加代码结构的复杂度,应用层心跳的流量消耗还是更大,毕竟这本质上还是个普通的数据包。
Nagle算法和粘包问题:
在TCP传输数据流中,存在两种类型的TCP报文段,一种包含成块数据,另一种则包含交互数据(通常只有携带几个字节数据)。
对于成块数据的报文段,TCP采用正常的流程发送即可,因为数据利用率很高。而对于交互数据的报文段,数据利用率就显得很低,在网络环境不好的情况下容易加重网络负担。所以TCP必须对交互数据单独处理。
nagle算法的核心思想是允许网络中最多只能有一个小分组被发送,而待发送的其它小分组会被重新分组成一个”较大的”小分组,等收到上一个小分组的应答后再发送。
Eg:客户端需要依次向服务器发送大小为1,2,3,1,2字节的5个分组
未开启nagle算法,调用五次send(),5个数据包
开启nagle算法,第一个包发送,其它四个进入发送缓存,等待第一个包应答确认,缓存中的四个包打包发送,共两个数据包。
优点:提高了数据利用率
缺点:对于实时性要求较高的(交互式)通讯有较大的延迟。
长连接:Client与Server先建立通讯连接,连接建立后不断开,然后再进行报文发送和接收。
短连接:Client方与Server每进行一次报文收发交易时才进行通讯连接,交易完毕后立即断开连接。此种方式常用于一点对多点通讯,比如多个Client连接一个Server。
保护消息边界:指传输协议把数据当作一条独立的消息在网上传输,接收端只能接收独立的消息。也就是说存在保护消息边界,接收端一次只能接收发送端发出的一个数据包。而面向流(会拆分)则是指无保护消息保护边界的,如果发送端连续发送数据,接收端有可能在一次接收动作中,会接收两个或者更多的数据包(消息)。
粘包出现原因
UDP不会出现粘包,因为它有消息边界
1发送端需要等缓冲区满才发送出去,造成粘包,Nagle算法。
发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
2接收方不及时接收缓冲区的包,造成多个包接收。
接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
避免粘包现象几种措施:
(1)对于发送方引起的粘包现象,关闭优化算法,及时传输,但效率低下。
(2)提高接收进程优先级,使其及时接收数据,从而尽量避免出现粘包现象;
粘包解决:(想办法加边界)
(1)发送固定长度的消息。
(2)把消息的尺寸与消息一块发送。封包,拆包。
(3)使用特殊标记来区分消息间隔。
TCP SYN泛洪攻击
1、TCP协议基本的漏洞
SYN洪泛攻击的基础是依靠TCP建立连接时三次握手的设计。第三个数据包验证连接发起人在第一次请求中使用的源IP地址上具有接受数据包的能力,即其返回是可达的。图1显示了一次普通的TCP连接开始时交换数据包的过程。
TCB(TCP 传输控制块)是一种包含一个连接所有信息的传输协议数据结构(实际上在许多操作系统中它是用于处理进站(inbound)连接请求的一个队列,该队列保存那些处于半开放(half-open)状态的TCP连接项目,和已建立完整连接但仍未由应用程序通过accept()调用提取的项目)。TCP的SYN-RECEIVED状态用于指出这个连接仅仅是半开连接,请求是否合法仍被质疑。
这就导致了一个明显潜在的DoS攻击,到达的SYN包将被分配过多的TCB而导致主机的内核内存被耗尽。为了避免这种内存耗尽,操作系统通常给监听接口关联了一个"backlog"队列参数,它同时维护连接的TCB上限数量和SYN-RECEIVED状态。尽管这种方案使主机的可用内存免遭攻击,但是backlog队列本身就带来了一个(小的)受攻击源。当backlog中没有空间时,就不可能再响应新的连接请求,除非TCB能被回收或者从SYN-RECIEVE状态中移除。
试图发送足够多的SYN包而耗尽backlog是TCP SYN洪泛的目的。攻击者在SYN包中加入源IP地址,这样就不会导致主机将已分配的TCB从SYN-RECEVIED状态队列中移除(因为主机将响应SYN-ACK)。因为TCP是可靠的,目的主机在断开半开连接并在SYN-RECIEVED队列中移除TCB之前将等待相当长的时间。在此期间,服务器将不能响应其他应用程序合法的新TCP连接请求。图2显示了简单的TCP SYN洪泛攻击的过程。
2、常用的泛洪攻击种类:
直接攻击
如果攻击者用他们自己的没有经过伪装的IP地址快速地发送SYN数据包,这就是所谓的直接攻击。然而,这种攻击要想奏效攻击者还必须阻止他的系统响应SYN-ACK包,因为任何ACK、RST或ICMP(Internet Control Message Protocol)包都将让服务器跳过SYN-RECEIVED状态(进入下一个状态)而移除TCB(因为连接已经建立成功或被回收了)。攻击者可以通过设置防火墙规则来实现,让防火墙阻止一切要到达服务器的数据包(SYN除外),或者让防火墙阻止一切进来的包来使SYN-ACK包在到达本地TCP处理程序之前就被丢弃了。
一旦被检测到,这种攻击非常容易抵御,用一个简单的防火墙规则阻止带有攻击者IP地址的数据包就可以了。这种方法在如今的防火墙软件中通常都是自动执行的。
欺骗式攻击
SYN洪泛攻击的另一种方式是IP地址欺骗。它比直接攻击方式更复杂一点,攻击者还必须能够用有效的IP和TCP报文头去替换和重新生成原始IP报文。
对于欺骗式攻击,首先需要考虑的就是选择地址。要使攻击成功,位于伪装IP地址上的主机必须不能响应任何发送给它们的SYN-ACK包。攻击者可以用的一个非常简单的方法,就是仅需伪装一个源IP地址,而这个IP地址将不能响应SYN-ACK包,或许因为这个IP地址上根本就没有主机,或许因为对主机的地址或网络属性进行了某些配置。另一种选择是伪装许多源地址,攻击者会假想其中的一些伪装地址上的主机将不会响应SYN-ACK包。要实现这种方法就需要循环使用服务器希望连接的源IP地址列表上的地址,或者对一个子网内主机做相同的修改。
如果一个源地址被重复地伪装,这个地址将很快被检测出来并被过滤掉。在大多数情况下运用许多不同源地址伪装将使防御变得更加困难。在这种情况下最好的防御方法就是尽可能地阻塞源地址相近的欺骗数据包。
分布式攻击
对于单个运用欺骗式攻击的攻击者真正的限制因素是如果这些伪装数据包能够以某种方式被回溯到其真正的地址,攻击者将被简单地击败。尽管回溯过程需要一些时间和ISP之间的配合,但它并不是不可能的。但是攻击者运用在网络中主机数量上的优势而发动的分布式SYN洪泛攻击将更加难以被阻止。如图3所示,这些主机群可以用直接攻击,也可以更进一步让每台主机都运用欺骗攻击。
如今,分布式攻击才是真正可行的,因为罪犯拥有数以千计的主机供他来进行拒绝服务(DoS)攻击。由于这些大量的主机能够不断地增加或减少,而且能够改变他们的IP地址和其连接,因此要阻止这类攻击目前还是一个挑战。
攻击的一些参数
SYN洪泛攻击能够比一般的仅仅是向目标网络发送大量数据包的蛮力DoS攻击用更少的数据包进行攻击。但是这需要对服务器的操作系统有一定了解,比如它分配了多少的backlog队列空间,在超时并丢弃TCB前它会将TCB在SYN-RECIEVED状态里保持多久。例如,攻击者可以发送刚好是backlog队列大小的一定数量的SYN包,并且其周期刚好是TCB被回收的时间,这样就可以让服务器永远不可用。
3、网络终端的对策
增加TCP backlog队列
由于其基本攻击原理是依赖于终端主机连接套接字的backlog溢出,因此一个显然的基于终端主机的解决方案是增加backlog队列大小,而且这种方法已经广泛的运用于大多数服务器了。增加backlog队列通常是通过修改应用的listen()函数调用和一个操作系统内核参数SOMAXCONN——它用于设置一个应用程序能够接收的backlog上限值。这种方法本身并不能被完全认为是抵御SYN洪泛的有效方法,即使在一些能够有效支持超大backlog队列分配的操作系统中,因为攻击者能够任意生成比其操作系统支持的backlog还大得多的数据报。
减少SYN-RECEIVED的时间
缩短一个TCB从进入SYN-RECEIVED状态到因未进入下一个状态而被回收之间的时间。但这个方案的一个明显缺点是攻击可以利用因拥塞而丢包的ACK-SYN或者握手完成的ACK包,这样合法连接的TCB就会由于主机忙于重传这些包(因为SYN-RECEIVED时间减少)而被回收。此外,在管理员减少SYN-RECEIVED状态时间多少和攻击者的发包率之间仅仅是一个线性关系而已。基于上述原因,此方案并不建议采用。
SYN缓存
基于SYN缓存,简化因接收SYN而生成TCB时初始化的状态,推迟全状态的实例化。在采用SYN缓存的主机中,一个带有被限制大小的HASH表空间被用于存放那些将被分配给TCB的数据的一个子集。如果当握手完成的ACK接收到了,这些数据将被复制到一个完整的TCB中,否则超出存活时间的HASH值将会在需要时被回收。
SYN缓存的数据结构对于那些试图让HASH表空间溢出的攻击者是健壮的。因为在其HASH值里面包含了对方的端口号和一些密码比特。由于堆栈相对于链表是一种更加高效的数据结构,因此堆栈被用于SYN缓存以提高速度。
SYN Cookies
对比SYN缓存的方法,SYN Cookies技术做到了接收到一个SYN时完全不需要分配空间。因为构成连接状态的最基本数据都被编码压缩进SYN-ACK的序列号比特位里了。对于一个合法连接,服务器将收到一个带有序列号(其实序列号已经加1)的ACK报文段,然后基本的TCB数据将被重新生成,一个完整的TCB通过解压确认数据将被安全的实例化。这种解压即使在重度攻击下仍然能够成功,因为在主机端根本没有任何存储负载,只有计算编码数据到ACK序列号中的负载。其不足之处就是,不是所有的TCB数据都能添加到32位的序列号段中,所以一些高性能要求的TCP选项将不能被编码。其另一个问题是这样的SYN-ACK报文段将不能被转发(因为转发需要完整的状态数据)。
4、基于网络的对策
过滤
网络层最基本的防御是RFC 2827里描述的过滤应用。采用输入源过滤,ISP拒绝将一个源IP地址不属于其来源子网的包进行更远的路由。输入源过滤能够有效地阻止用IP伪装的SYN洪泛攻击。然而这种方法在目前是没用的,因为其很难大规模部署。而且输入源过滤同样不能抵御分布式攻击。
防火墙与代理
一个有防火墙或者代理的设备在网络中就能够通过两种方法缓冲SYN洪泛攻击,一种是对连接发起人伪装SYN-ACK包,另一种是对服务器伪装ACK包。
如果连接发起人是合法的,防火墙/代理就会收到ACK,然后在它自己和服务器之间建立连接并伪装连接发起人的地址。防火墙/代理将连接双方分割开。这种分割能够抵御SYN洪泛攻击,因为服务器方根本没接受收过攻击者的SYN。只要防火墙/代理实现了一些基于TCP的防御策略,比如SYN cookies或SYN 缓存,他就能够保护所有在其后面的服务器免于SYN洪泛攻击。
另一种是响应SYN-ACK的伪装ACK包通过防火墙/代理到达服务器。这种伪装防止服务器的TCB一直停留在SYN-RECEIVED状态,因此保证了backlog队列中的空余空间。防火墙/代理将会停留等待一段时间,如果连接发起人正确的ACK没有被检测到,它将会通过伪装的TCP RST报文使服务器释放TCB。对合法的连接,数据包流能够在没有防火墙/代理的影响下继续进行。这种方法相比于上面伪装SYN-ACK的方法更具吸引力,因为当合法连接建立以后防火墙/代理不需要直接参与到连接中去。
交换机和路由器区别:
交换机在数据链路层,能识别 MAC 地址,根据 MAC 地址转发链路层数据帧。具有自学机制来维护 IP 地址与 MAC 地址的映射。
路由器位于网络层,能识别 IP 地址并根据 IP 地址转发分组。维护着路由表,根据路由表选择最佳路线。
网络编程一般步骤
TCP:
服务端:socket -> bind -> listen -> accept -> recv/send -> close。
客户端:socket -> connect -> send/recv -> close。
UDP:
服务端:socket -> bind -> recvfrom/sendto -> close。
客户端:socket -> sendto/recvfrom -> close。
TCP UDP的区别
TCP面向连接(三次握手),通信前需要先建立连接;UDP面向无连接,通信前不需要连接。
TCP通过序号、重传、流量控制、拥塞控制实现可靠传输;UDP不保障可靠传输,努力交付。
TCP面向字节流传输,因此可以被分割并在接收端重组;UDP面向数据报传输。
三次握手原因
如果仅两次连接可能出现一种情况:客户端发送完连接报文(第一次握手)后由于网络不好,延时很久后报文到达服务端,服务端接收到报文后向客户端发起连接(第二次握手)。此时客户端会认定此报文为失效报文,但在两次握手情况下服务端会认为已经建立起了连接,服务端会一直等待客户端发送数据,但因为客户端会认为服务端第二次握手的回复是对失效请求的回复,不会去处理。这就造成了服务端一直等待客户端数据的情况,浪费资源。
四次挥手原因:
TCP是全双工的,它允许两个方向的数据传输被独立关闭。当主动发起关闭的一方关闭连接之后,TCP进入半关闭状态,此时主动方可以只关闭输出流。
参考文献
TCP/IP详解卷1
Linux高性能服务器编程
计算机网络
西电计算机网络PPT
博客