求教关于FTP的问题,高手解答,在线等。
1 断开连接其实不区分客户端和服务器端,任何一方都可以调用close(or closesocket)之类
的函数开始主动终止一个连接。
2 当调用close函数断开一个连接时,主动断开的一方发送FIN报文给对方。当被动关闭的一方收到FIN报文时,它会发送ACK确认报文。因为TCP是双工的,也就是说,你可以想象一对TCP连接上有两条数据通路。当发送FIN报文时,意思是说,发送FIN的一端就不能发送数据,也就是关闭了其中一条数据通路。被动关闭的一端发送了ACK后,应用层通常就会检测到这个连接即将断开,然后被动断开的应用层调用close关闭连接。
3 一旦当你调用close(or closesocket),这一端就会发送FIN报文。也就是说,现在被动
关闭的一端也发送FIN给主动关闭端。有时候,被动关闭端会将ACK和FIN两个报文合在一起发送。主动关闭端收到FIN后也发送ACK,然后整个连接关闭。
4 你的补充应该是合理的,不过这只是程序的实现方式,你找一个ftp源码看看就知道了。
你可以根据服务器收到的数据的长度来判断,如果服务器收到的数据长度是0,那么意味着你的客户端程序已经断开了连接。从TCP/IP协议栈的角度来说,就是客户端程序关闭了自己写的这一半连接,向服务器发出了一个FIN。这涉及到TCP的状态迁移,关于这方面的知识,建议你看一下Richard Stevens先生的《TCP/IP 详解》卷一和《Unix网络编程》卷一,上面有详细的解释。
关于你的第二个问题,建议你仔细看一下自己的服务器程序代码。服务器程序首先要建立一个监听socket,当有客户端连接上来时,服务器会在一个新socket上接受客户端连接。所以并不存在“乱”的问题。关于这个问题同样推荐你看上面的两本关于网络编程的经典著作。
1网络紊乱
网络紊乱可能原因可能有很多,如路由器失败,主干网链接失败,或网线头松动都可能造成网络紊乱,最终造成网络或主机不可达。当发出去的包没有收到确认时,TCP会进行重传,直到中间的路由器发送一个ICMP消息来说明网络或主机不可达,然后发送RST。
2服务器进程崩溃
简单来说就是服务器主机上面的服务器进程挂掉了,服务器进程挂掉之后将会给对等方发送FIN,当发送FIN后并不表示服务器已经不能再接收数据了。当客户端接收到FIN后,再次给服务端发送数据,此时服务端会返回RST。如果客户端又一次给服务端发送数据,则此时客户端进程自动挂掉。
3服务器主机崩溃
在谈到这个问题时,不要把和服务端进程崩溃搞混了。服务器主机崩溃时是不会给对等方发送FIN的,这就是它们的区别。当服务器主机崩溃时,客户端啥都收不到。客户端向往常一样给服务器发数据,但是一直接收不到确认,客户端会进行超时重传,当重传达到一定次数就会返回超时,然后重置连接
4服务器主机崩溃后重启
当服务器主机崩溃后,原先的服务器进程不存在了,套接字也不存在了,故连接也不存在了。当服务器收到客户端发送的数据时,服务器会返回RST。
客户端发送完数据 发送一个Fin 告诉服务器发送完了,等待关闭
服务器收到 Fin后知道客户端已经发送完数据 应答ACK
服务器数据发送完毕要关闭链接 发送Fin
客户端收到Fin 知道服务器发送完毕 回复ACK 客户端关闭
服务器收到ACK 服务器关闭
如果没有收到ACK命令或者其他数据 计时器超时会自动中断连接
TCP是面向连接的协议。传输连接是用来传送TCP报文的,TCP连接传输的三个阶段分别为: 连接建立、数据传送和连接释放。
TCP连接的建立采用 客户服务器模式 。主动发起连接建立的应用进程叫做客户,而被动等待连接建立的应用进程叫做服务器。
TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段,三次握手的过程如下图所示。
(2) 第二次握手 :服务器收到 SYN报文段后,如同意连接,则服务器会为该TCP连接 分配缓存和变量 ,并向客户端返回 确认报文段 ,在确认报文段中同步位 SYN = 1 和 确认位 ACK = 1,确认号 ack = x + 1,同时也为自己选择一个初始序号 seq = y。这时TCP服务器进程进入 同步收到(SYN-RCVD) 状态。
(3) 第三次握手 :客户进程在收到服务器进程的确认报文后,客户端为该TCP连接 分配缓存和变量 ,并向服务器端返回一个报文段,这个报文段是对服务器确认报文段进行确认,该报文段中 ACK = 1,确认号 seq = y + 1,而自己序号为 x + 1(即第二次握手服务器确认报文段的确认号)。客户端在发送ACK报文段后进入 已建立连接(ESTABLISHED) 状态,这时TCP连接已经建立。
当服务器收到客户端的确认后,也进入 ESTABLISHED 状态。
这样选择序号的目的是为了 防止由于网络路由TCP报文段可能存在延迟抵达与排序混乱的问题,从而而导致某个连接的一方对它作错误的解释 。
下图表示了建立连接使用固定的序号存在的问题:
由于一个TCP连接是被一对端点所表示的,其中包括2个IP地址和2个端口号构成的4元组,因此即便是同一个连接也会出现不同的实例,如果连接由于某个报文段长时间延迟而关闭,然后又以相同的4元组被重新打开,那么可以相信延迟的报文段又会被视为有效据重新进入新连接的数据流中,这就会导致数据乱序问题。
为了避免上述的问题, 避免连接实例间的序号重叠可以将风险降至最低 。
如前文所述,一个TCP报文段只有同时具备连接的4元组与当前活动窗口的序列号,才会在通信过程中被对方认为是正确的。然而,这也反应了TCP连接的脆弱性:如果选择合适的序列号、IP地址和端口号,那么任何人都能伪造一个TCP报文段,从而打断TCP的正常连接。所以使用初始化序号的方式(通常随机生成序号)使得序列号变得难猜,或者使用加密来避免利用这种缺点被攻击。
所以,可以明白在建立TCP连接时,客户端和服务器端初始化序列号,就避免了上述的问题。前面说过,TCP序号占32位,范围是0~2 32 - 1,并且可以重用。
假如 第一次握手可以携带数据的话,如果有人使用伪TCP报文段恶意攻击服务器,那么每次都在第一次握手中的SYN报文中携带大量的数据,因为它不会理会服务器的发送和接收能力是否正常,不断地给服务器重复发送这样携带大量数据的SYN报文,这会导致服务器需要花费大量的时间和内存来接收这些报文数据,这会将导致服务器连接资源和内存消耗殆尽。
所以,之所以第一次握手不能携带数据,其中的一个原因就是 避免让服务器受到攻击 。而对于第三次握手,此时客户端已经建立了连接,通过前两次已经知道了服务器的接收正常,并且也知道了服务器的接收能力是多少,所以可以携带数据。
根据前面描述,在第一次握手,客户端向服务发送建立连接请求,第二次握手,服务器同意建立连接,并向客户端返回一个确认报文,至此客户端已经知道了服务器同意建立连接,为什么客户端还需要对服务器的允许连接报文段进行确认?
第三个ACK报文段的目的简单来说主要是为了 实现可靠数据传输 。
三次握手的目的不仅在于让通信双方了解一个连接正在建立,还在于利用数据包的选项来承载特殊的信息,交换初始序列号(Initial Sequence,ISN) 。为了实现可靠传输,TCP协议通信双方,都必须维护一个序列号,以标识发送出去的数据报中,哪些是已经被对方收到的。三次握手的过程是通信双方想要告知序列号起始值,并确认已经收到序列号的必经过程。
如上图,在两次握手过程中,通信双方都随机选择了自己的初始段序号,并且第二次握手的时候客户端收到了自己的确认序号,确认了自己的序列号,而服务器端还没有确认自己的序列号,没有收到确认序号, 如果这时候两次握手下就进行数据传递, 序号没有同步,数据就会乱序。即如果只是两次握手,最多只有客户端的起始序列号能被确认,而服务器断的序列号则得不到确认。
在三次握手的过程中,服务器为了响应一个受到的SYN报文段,会分配并初始化连接变量和缓存,然后服务器发送一个SYNACK报文段进行响应,并等待客户端的ACK报文段。如果客户不发送ACK来完成该三次握手的第三步,最终(通常在一分多钟之后)服务器将终止该半开连接并回收资源。
这种TCP连接管理协议的特性就会有这样一个漏洞,攻击者发送大量的TCP SYN报文段,而不完成第三次握手的步骤。随着这种SYN报文段的不断到来,服务器不断为这些半开连接分配资源,从而导致服务器连接资源被消耗殆尽。这种攻击就是 SYN泛供攻击 。
为了应对这种攻击,现在有一种有效的防御系统,称为 SYN cookie 。SYN cookie的工作方式如下:
连接释放的四次挥手过程如下图所示:
(2) 第二次挥手 :服务器收到连接释放报文段后即发出确认,确认为ACK = 1,确认号为ack = u + 1,序号seq = v(其值是服务器前面已传送过的数据最后一个字节的序号加1),然后服务器就进入了 关闭等待(CLOSE-WAIT) 状态。
(3) 第三次挥手 :如果此时服务器没有数据要发送了,此时服务器向客户端发出 连接释放报文段 ,其FIN = 1,假设器序号为seq = w(在半关闭状态下服务器可能又发送了一些数据),服务器必须重复上次以发送的确认号ack = u + 1(因为客户端没有向服务器发送过数据,所以确认号和上次一致)。这时,服务器进入 最后确认(LAST-ACK) 状态,等待客户端的确认。
(4) 第四次挥手 :客户端在收到服务器端发出的连接释放报文段后,必须对此发出确认,在确认报文段中将ACK置位1,确认号ack = w + 1,而自己的序号为seq = u + 1。之后客户端进入 时间等待(TIME-WAIT) 状态。在经过 时间等待计时器 设置的时间 2MSL 后,客户端才进入 关闭(CLOSE) 状态
这是为了 保证客户端发送的最后一个ACK报文段能够到达服务器端。
客户端发送的ACK报文段可能丢失,因而使服务器收不到对自己已发送的释放连接报文段的确认。服务器会重传连接释放报文段,重新启动2MSL计时器,最终,客户端和服务器端都能进入CLOSE状态。
在建立连接时,服务器端处于LISTEN状态时,当收到SYN报文段的建立连接请求后,它可以把ACK报文段和SYN报文段(ACK报文段起确认作用,即确认客户端的连接建立请求;SYN报文段起同步作用)放在一起发送,所以在连接建立时四次握手(即第二次握手时,服务器的ACK报文段和SYN报文段分开发送)可以合并为三次握手。
而在释放连接时需要四次是因为 TCP连接的半关闭造成的 。由于TCP是 全双工 的(即数据可在两个方向上同时传递),因此,每个方向都必须要单独进行关闭,这个单方向的关闭就叫 半关闭 。在关闭连接时,当服务器收到客户端的FIN报文通知时,它仅仅表示客户端没有数据发送服务器了;但服务器未必将所有的数据都全部发送给了客户端,所以服务器端未必马上也要关闭连接,也即服务器端可能还需要发送一些数据给客户端之后,再发送FIN报文给客户端来表示现在可以关闭连接了,所以 它这里的ACK报文和FIN报文多数情况下都是分开发送的 ,这也是为什么释放连接时需要交换四次报文了。
如果客户端断开连接,应该向服务器发送“客户端断开连接”的提示。原因是,服务器需要知道客户端是否断开连接,以便及时清理已经断开的连接资源,防止资源浪费和影响系统性能。
当客户端主动断开连接时,服务器需要清理与该客户端相关的资源,例如客户端的连接信息和状态,以及与该客户端相关的数据缓存等。如果服务器无法及时清理这些资源,会导致系统性能下降,甚至出现崩溃的情况。因此,向服务器发送“客户端断开连接”的提示是非常必要的。
此外,对于服务器而言,还需要对客户端是否异常断开连接进行判断和处理。如果客户端异常断开连接,可能是由于网络故障等原因造成的,这时服务器需要及时检测连接状态,重新建立连接或者进行其他处理,以保证服务器端的正常运行。
总之,向服务器发送“客户端断开连接”的提示,可以让服务器及时清理断开的连接资源,避免出现性能问题和崩溃的情况,保证系统的稳定性和可靠性。
TCP 传输链接的释放
当 TCP 连接建立以后,就可以在两个方向传送数据流。当 TCP 的网络应用进程再没有数据需要发送的时候,就可以发出关闭连接命令,释放连接。TCP 是通过发送 FIN 字段置1的数据段来作为关闭传输连接的命令,从而关闭本端数据流的,但是本端仍还可以继续接收来自对端的数据,直到对端也使用了同样的方法关闭那个方向的数据流为止,,这时整个双方传输连接就彻底关闭了。
单方面主动关闭的 TCP 连接释放过程
相对 TCP 传输连接建立的三次握手过程来说,TCP 传输连接的释放过程要稍微复杂一些,需要经过四次握手过程。这是由 TCP 的半关闭(half-closed)特性造成的,因为这一个 TCP 连接是全双工(即数据在两个方向上能同时传递),每个方向必须单独进行关闭。TCP 传输连接关闭原则如下:当一端完成它的数据发送任务后就可以发送一个 FIN 字段值置1的数据段来终止这个方向的数据发送;当另一端收到这个 FIN 数据段后,必须通知它的应用层“对端已经终止了这个方向的数据发送”。而 FIN 数据段的发送是由应用层调用 CLOSE 服务原语的结果。TCP 连接释放的四次握手过程如下图所示,具体描述如下。
TCP传输连接释放的四次握手过程
一开始,通信双方都处于 ESTABLISHED (连接建立)状态。如果客户端认为数据全部发送完了,想结束本次传输连接,则由应用层的对应应用调用 CLOSE 服务原语,然后向服务器发送一个 FIN 字段值置1的数据段(假设此数据段的序号为m),客户端进入 FIN WAIT 1 状态,等待服务器的确认。
服务器在收到客户端发来的 FIN 数据之后,确认客户端没有新的数据要发送了,向客户端发送一个 ACK 字段值置1、确认号为 m+1 的数据段(假设此数据段的序号为 w,服务端与客户端的数据段序号可以不一样),表示前面的数据已全部收到了,然后进入 CLOSE WAIT (关闭等待)状态。与此同时,服务器的TCP实体通知对应的应用进程,释放从客户端到服务器方向的传输连接,进入半关闭状态。但此时服务器仍可以向客户端发送数据段,客户端也可以接受来自服务器的数据,而且这可能持续一段时间,直到服务器的数据也全部发送完毕。
当客户端收到服务器的 ACK 数据段之后,进入 FIN WAIT 2 状态,进一步等待服务器发出连接释放的数据段。
当服务器发送完全部的数据后,其对应的应用进程也会通知 TCP 实体释放此方向的TCP传输连接,向客户端发送 FIN 字段置1、ack = m+1(假设此时的数据段序号已变为 w)的确认数据段。这时服务器进入 LAST ACK (最后确认)状态,等待客户端的确认。
客户端在收到服务器的 FIN+ACK 数据段后,,向服务发送一个 ACK 字段值为1、ack = w+1、序号为m+1 的数据段,进入 TIME WAIT 状态。但此时 TCP 连接还没有释放,必须等待 2MSL 时间(RFC793 建议设置 MSL 为2分钟)后,客户端才进入到 CLOSED 状态,彻底释放了 TCP 连接。
服务器在接收到客户端发来的 ACK 数据段后,也进入 CLOSED, 彻底释放连接。此时,已经完成了这个 TCP 传输连接过程。
双方主动关闭的 TCP 连接释放流程
与可以双方同时建立 TCP 传输连接一样,TCP 传输连接关闭也可以由双方同时主动进行(正常情况下都是由一方发送第一个 FIN 数据段进行主动连接关闭,另一方被动接受连接关闭),如下图所示。具体描述如下。
主动同时关闭TCP连接过程
当两端对应的网络应用层进程同时调用 CLOSE 原语,并发送 FIN 数据段执行关闭命令时,两端均从 ESTABLISHED 状态转变为 FIN WAIT 1 状态。任意一端收到对端发来的 FIN 数据段后,其状态均由 FIN WAIT 1 转变到 CLOSING 状态,并发送最后的 ACK 数据段。当收到最后的 ACK 数据段后,状态转变为 TIME_WAIT,在等待 2MSL 后进入到 CLOSED 状态,最终释放这个TCP连接。
0条评论