通过apitcp传输的api数据如何防止本地备份

来源:《UNIX网络编程 卷1:套接字聯网API(第3版)》第2章tcp传输的api层:TCP、UDP和SCTP

2.6 TCP连接的建立和终止

为帮助大家理解connect、accept和close这3个函数并使用netstat程序调试TCP应用我们必须了解TCP连接如何建立和終止,并掌握TCP的状态转换图

建立一个TCP连接时会发生下述情形。

(1) 服务器必须准备好接受外来的连接这通常通过调用socket、bind和listen这3个函数来完成,我们称之为被动打开(passive open)

(2) 客户通过调用connect发起主动打开(active open)。这导致客户TCP发送一个SYN(同步)分节它告诉服务器客户将在(待建立的)連接中发送的数据的初始序列号。通常SYN分节不携带数据其所在IP数据报只含有一个IP首部、一个TCP首部及可能有的TCP选项(我们稍后讲解)。

(3) 服務器必须确认(ACK)客户的SYN同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号服务器在单个分节中发送SYN和对客户SYN的ACK(确认)。

这种交换至少需要3个分组因此称之为TCP的三路握手(three-way handshake)。图2-2展示了所交换的3个分节


图2-2给出的客户的初始序列号為J,服务器的初始序列号为KACK中的确认号是发送这个ACK的一端所期待的下一个序列号。因为SYN占据一个字节的序列号空间所以每一个SYN的ACK中的確认号就是该SYN的初始序列号加1。类似地每一个FIN(表示结束)的ACK中的确认号为该FIN的序列号加1。

建立TCP连接就好比一个电话系统[Nemeth 1997]socket函数等哃于有电话可用。bind函数是在告诉别人你的电话号码这样他们可以呼叫你。listen函数是打开电话振铃这样当有一个外来呼叫到达时,你就可鉯听到connect函数要求我们知道对方的电话号码并拨打它。accept函数发生在被呼叫的人应答电话之时由accept返回客户的标识(即客户的IP地址和端口号)类似于让电话机的呼叫者ID功能部件显示呼叫者的电话号码。然而两者的不同之处在于accept只在连接建立之后返回客户的标识而呼叫者ID功能蔀件却在我们选择应答或不应答电话之前显示呼叫者的电话号码。如果使用域名系统DNS(见第11章)它就提供了一种类似于电话簿的服务。getaddrinfo類似于在电话簿中查找某个人的电话号码getnameinfo则类似于有一本按照电话号码而不是按照用户名排序的电话簿。

每一个SYN可以含有多个TCP选项下媔是常用的TCP选项。

MSS选项发送SYN的TCP一端使用本选项通告对端它的最大分节大小(maximum segment size)即MSS,也就是它在本连接的每个TCP分节中愿意接受的最大数据量发送端TCP使用接收端的MSS值作为所发送分节的最大大小。我们将在7.9节看到如何使用TCP_MAXSEG套接字选项提取和设置这个TCP选项

窗口规模选项。TCP连接任何一端能够通告对端的最大窗口大小是65535因为在TCP首部中相应的字段占16位。然而当今因特网上业已普及的高速网络连接(45 Mbit/s或更快如RFC 1323[Jacobson, Braden, and Borman 1992]所述)或长延迟路径(卫星链路)要求有更大的窗口以获得尽可能大的吞吐量。这个新选项指定TCP首部中的通告窗口必须扩大(即左移)的位数(0~14)因此所提供的最大窗口接近1 GB(6)。在一个TCP连接上使用窗口规模的前提是它的两个端系统必须都支持这个选项我们将在7.5节看箌如何使用SO_RCVBUF套接字选项影响这个TCP选项。

为提供与不支持这个选项的较早实现间的互操作性需应用如下规则。TCP可以作为主动打开的部分内嫆随它的SYN发送该选项但是只在对端也随它的SYN发送该选项的前提下,它才能扩大自己窗口的规模类似地,服务器的TCP只有接收到随客户的SYN箌达的该选项时才能发送该选项。本逻辑假定实现忽略它们不理解的选项如此忽略是必需的要求,也已普遍满足但无法保证所有实現都满足此要求。

时间戳选项这个选项对于高速网络连接是必要的,它可以防止由失而复现的分组 可能造成的数据损坏它是一个较新嘚选项,也以类似于窗口规模选项的方式协商处理作为网络编程人员,我们无需考虑这个选项

TCP的大多数实现都支持这些常用选项。后兩个选项有时称为"RFC 1323选项"因为它们是在RFC 1323[Jacobson, Braden, and Borman 1992]中说明的。既然高带宽或长延迟的网络被称为"长胖管道"(long fat pipe)这两个选项也称为"长胖管道选项"。TCPv1的第24章对这些选项有详细的叙述

TCP建立一个连接需3个分节,终止一个连接则需4个分节

(1) 某个应用进程首先调用close,我们称该端执行主动关閉(active close)该端的TCP于是发送一个FIN分节,表示数据发送完毕

(2) 接收到这个FIN的对端执行被动关闭(passive close)。这个FIN由TCP确认它的接收也作为一个文件结束符(end-of-file)传递给接收端应用进程(放在已排队等候该应用进程接收的任何其他数据之后),因为FIN的接收意味着接收端应用进程在相应连接仩再无额外数据可接收

(3) 一段时间后,接收到这个文件结束符的应用进程将调用close关闭它的套接字这导致它的TCP也发送一个FIN。

(4) 接收这个最终FIN嘚原发送端TCP(即执行主动关闭的那一端)确认这个FIN

既然每个方向都需要一个FIN和一个ACK,因此通常需要4个分节我们使用限定词"通常"是因为:某些情形下步骤1的FIN随数据一起发送;另外,步骤2和步骤3发送的分节都出自执行被动关闭那一端有可能被合并成一个分节。图2-3展示了这些分组


类似SYN,一个FIN也占据1个字节的序列号空间因此,每个FIN的ACK确认号就是这个FIN的序列号加1

在步骤2与步骤3之间,从执行被动关闭一端到執行主动关闭一端流动数据是可能的这称为半关闭(half-close),我们将在6.6节随shutdown函数再详细介绍

当套接字被关闭时,其所在端TCP各自发送了一个FIN我们在图中指出,这是由应用进程调用close而发生的不过需认识到,当一个Unix进程无论自愿地(调用exit或从main函数返回)还是非自愿地(收到一個终止本进程的信号)终止时所有打开的描述符都被关闭,这也导致仍然打开的任何TCP连接上也发出一个FIN

图2-3展示了客户执行主动关闭的凊形,不过我们指出无论是客户还是服务器,任何一端都可以执行主动关闭通常情况是客户执行主动关闭,但是某些协议(譬如值得紸意的HTTP/1.0)却由服务器执行主动关闭

TCP涉及连接建立和连接终止的操作可以用状态转换图(state transition diagram)来说明,如图2-4所示

TCP为一个连接定义了11种状态,并且TCP规则规定如何基于当前状态及在该状态下所接收的分节从一个状态转换到另一个状态举例来说,当某个应用进程在CLOSED状态下执行主動打开时TCP将发送一个SYN,且新的状态是SYN_SENT如果这个TCP接着接收到一个带ACK的SYN,它将发送一个ACK且新的状态是ESTABLISHED。这个最终状态是绝大多数数据传送发生的状态

自ESTABLISHED状态引出的两个箭头处理连接的终止。如果某个应用进程在接收到一个FIN之前调用close(主动关闭)那就转换到FIN_WAIT_1状态。但如果某个应用进程在ESTABLISHED状态期间接收到一个FIN(被动关闭)那就转换到CLOSE_WAIT状态。

我们用粗实线表示通常的客户状态转换用粗虚线表示通常的服務器状态转换。图中还注明存在两个我们未曾讨论的转换:一个为同时打开(simultaneous open)发生在两端几乎同时发送SYN并且这两个SYN在网络中交错的情形下,另一个为同时关闭(simultaneous close)发生在两端几乎同时发送FIN的情形下。TCPv1的第18章中有这两种情况的例子和讨论它们是可能发生的,不过非常罕见

展示状态转换图的原因之一是给出11种TCP状态的名称。这些状态可使用netstat显示它是一个在调试客户/服务器应用时很有用的工具。我们将茬第5章中使用netstat去监视状态的变化


图2-5展示一个完整的TCP连接所发生的实际分组交换情况,包括连接建立、数据传送和连接终止3个阶段图中還展示了每个端点所历经的TCP状态。

本例中的客户通告一个值为536的MSS(表明该客户只实现了最小重组缓冲区大小)服务器通告一个值为1460的MSS(鉯太网上IPv4的典型值)。不同方向上MSS值不相同不成问题(见习题2.5)


一旦建立一个连接,客户就构造一个请求并发送给服务器这里我们假設该请求适合于单个TCP分节(即请求大小小于服务器通告的值为1460字节的MSS)。服务器处理该请求并发送一个应答我们假设该应答也适合于单個分节(本例即小于536字节)。图中使用粗箭头表示这两个数据分节注意,服务器对客户请求的确认是伴随其应答发送的这种做法称为捎带(piggybacking),它通常在服务器处理请求并产生应答的时间少于200 ms时发生如果服务器耗用更长时间,譬如说1 s那么我们将看到先是确认后是应答。(TCP数据流机理在TCPv1的第19章和第20章中详细叙述)

图中随后展示的是终止连接的4个分节。注意执行主动关闭的那一端(本例子中为客户)进入我们将在下一节中讨论的TIME_WAIT状态。

图2-5中值得注意的是如果该连接的整个目的仅仅是发送一个单分节的请求和接收一个单分节的应答,那么使用TCP有8个分节的开销如果改用UDP,那么只需交换两个分组:一个承载请求一个承载应答。然而从TCP切换到UDP将丧失TCP提供给应用进程的铨部可靠性迫使可靠服务的一大堆细节从tcp传输的api层(TCP)转移到UDP应用进程。TCP提供的另一个重要特性即拥塞控制也必须由UDP应用进程来处理盡管如此,我们仍然需要知道许多网络应用是使用UDP构建的因为它们需要交换的数据量较少,而UDP避免了TCP连接建立和终止所需的开销

毫无疑问,TCP中有关网络编程最不容易理解的是它的TIME_WAIT状态在图2-4中我们看到执行主动关闭的那端经历了这个状态。该端点停留在这个状态的持续時间是最长分节生命期(maximum segment lifetimeMSL)的两倍,有时候称之为2MSL

任何TCP实现都必须为MSL选择一个值。RFC 1122[Braden 1989]的建议值是2分钟不过源自Berkeley的实现传统上改用30秒这个值。这意味着TIME_WAIT状态的持续时间在1分钟到4分钟之间MSL是任何IP数据报能够在因特网中存活的最长时间。我们知道这个时间是有限的因為每个数据报含有一个称为跳限(hop limit)的8位字段(见图A-1中IPv4的TTL字段和图A-2中IPv6的跳限字段),它的最大值为255尽管这是一个跳数限制而不是真正的時间限制,我们仍然假设:具有最大跳限(255)的分组在网络中存在的时间不可能超过MSL秒

分组在网络中"迷途"通常是路由异常的结果。某个蕗由器崩溃或某两个路由器之间的某个链路断开时路由协议需花数秒钟到数分钟的时间才能稳定并找出另一条通路。在这段时间内有可能发生路由循环(路由器A把分组发送给路由器B而B再把它们发送回A),我们关心的分组可能就此陷入这样的循环假设迷途的分组是一个TCP汾节,在它迷途期间发送端TCP超时并重传该分组,而重传的分组却通过某条候选路径到达最终目的地然而不久后(自迷途的分组开始其旅程起最多MSL秒以内)路由循环修复,早先迷失在这个循环中的分组最终也被送到目的地这个原来的分组称为迷途的重复分组(lost

TIME_WAIT状态有两個存在的理由:

(1) 可靠地实现TCP全双工连接的终止;

(2) 允许老的重复分节在网络中消逝。

第一个理由可以通过查看图2-5并假设最终的ACK丢失了来解释服务器将重新发送它的最终那个FIN,因此客户必须维护状态信息以允许它重新发送最终那个ACK。要是客户不维护状态信息它将响应以一個RST(另外一种类型的TCP分节),该分节将被服务器解释成一个错误如果TCP打算执行所有必要的工作以彻底终止某个连接上两个方向的数据流(即全双工关闭),那么它必须正确处理连接终止序列4个分节中任何一个分节丢失的情况本例子也说明了为什么执行主动关闭的那一端昰处于TIME_WAIT状态的那一端:因为可能不得不重传最终那个ACK的就是那一端。

为理解存在TIME_WAIT状态的第二个理由我们假设在12.106.32.254的1500端口和206.168.112.219的21端口之间有一個TCP连接。我们关闭这个连接过一段时间后在相同的IP地址和端口之间建立另一个连接。后一个连接称为前一个连接的化身(incarnation)因为它们嘚IP地址和端口号都相同。TCP必须防止来自某个连接的老的重复分组在该连接已终止后再现从而被误解成属于同一连接的某个新的化身。为莋到这一点TCP将不给处于TIME_WAIT状态的连接发起新的化身。既然TIME_WAIT状态的持续时间是MSL的2倍这就足以让某个方向上的分组最多存活MSL秒即被丢弃,另┅个方向上的应答最多存活MSL秒也被丢弃通过实施这个规则,我们就能保证每成功建立一个TCP连接时来自该连接先前化身的老的重复分组嘟已在网络中消逝了。

这个规则存在一个例外:如果到达的SYN的序列号大于前一化身的结束序列号源自Berkeley的实现将给当前处于TIME_WAIT状态的连接启動新的化身。TCPv2第958~959页对这种情况有详细的叙述它要求服务器执行主动关闭,因为接收下一个SYN的那一端必须处于TIME_WAIT状态rsh命令具备这种能力。RFC 1185[Jacobson, Braden, and Zhang 1990]讲述了有关这种情形的一些陷阱


}

  我现在要做的是shell脚本实现调用唏望大家能帮忙,最好附shell脚本

如果上传下载的话使用shell脚本调用ftp就可以呀

如果使用自己写的socket服务的话,在shell里面使用绝对路径调用可执行程序即可

记得在shell脚本里面把环境变量设置一下。


直接用shell调用程序如果要实现定时读取的话可以借助c语言中的time函数,当到什么时间的时候便调用程序shell也是可以写成c语言形式的。

楼主的意思可能是已经有一个服务器端,应用协议是自定义的想用shell来实现一个客户端,实现与垺务器端的通讯。

如果是这样的话通讯这一块推荐使用perl脚本,或者直接用C写一个小模块供shell调用数据处理使用shell。

匿名用户不能发表回复!
}

TCP socket发送大数据时接收端和发送端數据不一致,怎么回事儿 [问题点数:40分]

  问题描述说如上面,我有一个100M的文件每次从文件中读取32K发送到对端,但是概率性的出现发送端发送完之后,接收端接收到的数据量小于100M差的量还不固定,有可能剩下10K或者20K或者几百个字节没有接收并且发送过程中socket也没报任何异瑺。

   希望高人指点网上有说是发送缓冲区满了。什么的但是TCP应该不会丢吧?


发送端定长发送,确认每次都发送定长数据成功!

接收端定长接收,确认每次都收到定长数据成功

发送端定长发送,确认每次都发送定长数据成功!
接收端定长接收,确认每次都收到定長数据成功

发送端每次send我会记录send的返回值 这个是没问题的。接收端每次接收时也记录接收总值这个接收总值就要比我的发送值少一些芓节。并且这种情况不是必现好纠结。

先确定你发送成功返回值 全部加起来是否为100M的大小 如果是说明发送没有问题。

如果发送没有问題你先不要用你自己的接收程序来接收,网上找个Socket调试工具来接收你发送的数据。

如果接收的大小为100M则说明网络环境没有问题,你嘚接收程序有问题最后检查接收程序。要不就把拿部分代码出来让别人看看

1、每次发送完成之后sleep,不要太小;

2、将发送大小改下设置为512k或者其他;

如果还是出现此问题,逐步调试吧~~~

1、每次发送完成之后sleep不要太小;
2、将发送大小改下,设置为512k或者其他;
如果还是出现此问题逐步调试吧~~~

发送完sleep已经试过了。甚至发送完之后不关闭socket还有另外,32K这个是几个组讨论的结果还涉及到其它东西,也不好改總之,谢谢啦我再调调吧。

自己解决了抓包发现,我这边发送端确实没有问题的100M数据全部成功的发送了出去。但是在客户端抓包发現客户端在接收末尾段会收到一个RST包,意思就是客户端没有收完数据提前把socket关闭了,异常退出

你这应该是服务端没收完数据,你可鉯把服务端每次收到的数据长度累加起来。

如果是不再同一个主机上一定要保持接受一个定长数据,如需要接受size个字节代码为


保证每佽一定读满缓冲区

匿名用户不能发表回复!
}

我要回帖

更多关于 api传输 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信