使用TCP协议连续传输大量数据时,是否会丢包,因如何避免?

chengwei_xj 2003-09-23 10:54:08
加精
比如发送文件。记得有人提过可能会发生什么堆栈溢出。
怎样避免呢?
是不是可以收到数据后发送确认包,收到确认包后再继续发送。或是发送方发送了一些数据后sleep一下。

还有,我们都知道,使用UDP协议发送包时需要确认,但TCP协议时面向连接的可靠传输,是不是发出的包肯定可以收到,不需要确认呢?
...全文
4028 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
chengwei_xj 2003-12-02
  • 打赏
  • 举报
回复
很高兴自己的帖子能够引起大家广泛深入的讨论,谢谢大家.
pc200300 2003-10-18
  • 打赏
  • 举报
回复
我想发表一下自己的看法:
(1)如果网线等硬件出现故障,比如网线断了、一方的SOCKET没有任何反映,所以检验一个连接是否正常,通常采用心跳测试;
(2)send()等函数只是把你要发送的数据写入你的SOCKET缓冲区,并不保证对方能正确接收到;
(3)TCP是一个可靠的连接,它有自己的一套安全机制,但也不能保证对方能正确接收到;
(4)我的解决方案:自己定义一套应用层的数据传输规约,通过搂上几位提供的方法,可以定义一套安全性很好的规约。
wwwdfq1977 2003-10-17
  • 打赏
  • 举报
回复
能不能检测到错误和我的说法有矛盾吗?
send函数确实不是仅仅把数据传递给传输层,但是,他一定要等待对方应答后才返回吗?难道有错误就不能在下一次调用时返回
缓冲区太大,有时延,这和他收到了确认信息有什么关系,因为它完全可能作其他工作
注意tcp协议所在的线程和应用程序不再同一个线程内,并不是send一返回tcp就什么都不干了,在此期间他完全可能作一些诸如设置错误或正常状态一类工作,以便程序下次调用send或者closeSocket时返回这些错误

我觉得你还是好好看一看前面的所有贴子吧。
xiaohyy 2003-10-17
  • 打赏
  • 举报
回复
想说说关于send函数的问题。send应该是对方收到确认后才返回的,很简单,从send函数的返回错误信息就可以看出,这里随便举几个

WSAETIMEDOUT:该错误是由于网络故障或远程主机当机等原因导致的异常中止连接

还有WSAECONNRESET错误,这是由远程主机上的程序强行退出或死掉引起的。

,如果按照wwwdfq1977(qswl) 的说法只是把数据发送到本机的传输层,又怎么能检测出这些问题?

还有大家在send函数处设置断点,如果缓冲区够大,也不是立即返回,还是有一定的时延的。这也说明send函数做了一些底层的工作,接收了对方的确认信息

廖雪峰 2003-10-15
  • 打赏
  • 举报
回复
我认为楼主的问题是:是否应该使用应答机制来保证不丢包

但是设计tcp协议的目的就是使用应答机制来确保可靠传输,tcp已经在传输层实现了这一机制,如果自己在应用层在实现一次,有什么意义呢?还不如改用udp。

tcp本身就是用滑动窗口模型,对每个包都会确认,使用tcp连接关心的是处理建立连接和关闭连接,以及连接中断引发的异常,对传送数据你就应该完全交给tcp。

我们在学校下电影常常一个文件600-700M,传输速度500k-2MB/s,如果tcp不可靠,用ftp怎么保证一次下载几个G不出错?ftp协议是基于tcp的。
esdn 2003-10-14
  • 打赏
  • 举报
回复
关于wwwdfq1977(qswl) 和asklxf(xuefeng)的讨论,在网络编程里这样的深入不很多见,我想发表一下我的看法。
首先,tcp协议send函数调用后,应用程序里的数据肯定是被传到TCP/IP协议占的TCP的发送缓冲区里了。
然后,当send函数返回到应用程序时,数据是否发送出去要看Nagle算法开没开。
1.如果不开Nagle算法,发送方的TCP/IP协议占则执行发送动作。
2.如果开了,看看发送条件是否满足(如缓冲区是否有一个MSS的数据),不满足则不发送而返回
满足则发送之后再返回。
至于对方是否收到并进一步发确认,仅就此无法判断。
基本原理这样了,具体系统实现可能还有机制
ypos 2003-10-13
  • 打赏
  • 举报
回复
在TCP上再实现一个窗口控制,缓冲区,确认发送如何?
deva 2003-10-13
  • 打赏
  • 举报
回复
tcp的作用就是可靠性传播
但如果是大量数据而且网络很快就会出现sequence的重复
这才是最主要的问题!!
xlfrd 2003-10-11
  • 打赏
  • 举报
回复
如果是blocking模式send应该是得到对方TCP协议确认后才返回而不是仅仅得到本机TCP模块回应就返回,否则send永远都返回成功,可以如下测试一下,建立连接后断开物理线路,操作系统不会立即得知物理链路已断开(如拨号),程序再调用send,如果返回失败说明send是等待确认后才返回,如果返回成功就说明send只需要发到本机TCP就返回。
awjx 2003-10-11
  • 打赏
  • 举报
回复
我在tcp/ip上学的,怎么与上楼上,上的有很多不同呀?
廖雪峰 2003-10-06
  • 打赏
  • 举报
回复
每种语言的send函数都不一样啊

如果是异步调用,不保证正确发送

但是我用的是java.net.Socket

只要不发生IOException,那肯定正确发送出去了
netsys2 2003-09-30
  • 打赏
  • 举报
回复
没有任何一个函数,协议可以保证完全不丢包,

只不过TCP要好得多,因为它是具有连接和错误重发的协议。

在极端情况下(通信线路突然中断),那么TCP可以报错,应用程序可以重新建立连接再重传。

但是中间如果有第三方攻击(如窃听者或者线路故障),那么TCP也不能保证你的数据完全到了对方,因此在关键的数据交互场合(如网上交易),必须通过应用层的协议加以控制。
wwwdfq1977 2003-09-30
  • 打赏
  • 举报
回复
再说一句,tcp不会丢包和send返回ok接受方一定收到没有任何关系,前者并不意味着后者
wwwdfq1977 2003-09-30
  • 打赏
  • 举报
回复
楼上:我不太同意你关于send函数的说法
首先必须明确send函数究竟作了什么,他是负责将数据传递给本地tcp层后返回,还是同时负责将应用层传递的数据得到接受方tcp层确认后才返回
如果是后者你说的无疑是正确的,但是,事实上完全不是这样,这是因为如果这样,那么nagle算法就没用了,因为这个算法就是将多次send函数的传入的小数据拼凑成为一个较大的包,然后再发送。
可见,即使是send函数ok了,对方也不一定可以接受到,因为tcp协议只是在tcp层上尽他的义务,而send函数只不过扮演了一个应用层向tcp层传递数据的角色,除此之外,他和tcp层没有任何关系。
还有一种特殊情况,虽说非常罕见,但是并非不可能发生,那就是:如果接受方tcp层确实接受到数据并向发送方发送了确认信息,但是,在他向应用层传递数据时,应用层程序突然崩溃,那么接受方的应用程序也是无法接受到数据的,而此时,发送方tcp层得到了确认信息认为这些数据已经发送成功了,这是<tcp/ip高级编程>一书里举的极端例子,不信的话你可以看一看这本书吧
总之,不要把send函数和tcp协议混在一起,send函数并不是tcp协议里面的东西,send函数并不能保证任何东西,而这些保证是由tcp来完成的
廖雪峰 2003-09-29
  • 打赏
  • 举报
回复
使用TCP协议在任何时候都不会丢包,因为:

TCP/IP模型中,IP层负责发送包但不保证正确接收,而TCP层在IP层上,保证每个包正确接收。

在应用程序中,如果用Socket的send发送一段数据,只要函数返回OK,对方肯定正确接收了。

使用TCP传送数据不用关心数据是否正确接收(TCP保证做到)更不用自己写应答机制(TCP对每个包都作应答)否则就成udp了。

如果网络故障,socket会有错误报告,tcp连接会断开,但是已发送的数据肯定正确发送了,你所需要的就是试图重新连接,然后把没有发送的数据接着发送出去。
zihan 2003-09-29
  • 打赏
  • 举报
回复
同意楼上的了.的确,tcpip会帮你确认你的包信息,但是如果由于网络异常引起的,有些时候tcpip也不能够帮你解决,所以建议把东西保存为一个文件,然后分块发送,然后自己添加头尾信息,

不过一般情况下没有这个必要了.
wwwdfq1977 2003-09-28
  • 打赏
  • 举报
回复
我觉得很多人没有理解tcp/ip的分层概念
用tcp协议时,用send函数发送数据成功,应该指的是应用层向本机tcp那一层传递数据成功,而并非指这些数据已经得到对方tcp层确认.
如果连接正常,你向本机tcp层传递的数据,对方tcp层绝对可以正确收到,这是tcp协议可以保证的,否则tcp的可靠就没有意义了.但是如果网络突然中断了,那么尚还在本机tcp协议栈中未发完的数据将可能被丢弃,因此如果连接中断后你又重新连接发送数据时,你发送数据的依据不能由你传给本机tcp层多少数据来决定,而是应该询问对方应用层已经收到了多少数据
如果你的程序要求发送的数据必须一字不漏的被接受方收到,那么你必须把发送的数据存为文件,然后发送,发送的规则如上所述,另外,文件传完时也应该确认,但是你没必要每个包都确认。
如果没有这个必要,那么你就用不着确认
ypos 2003-09-28
  • 打赏
  • 举报
回复
TCP连接在不断开的情况下可以保证不丢数据
系统的IP协议栈的缓冲区溢出不叫溢出,只能说是丢弃包,属于正常现象,只是会影响性能,而且TCP自己就有流控,你做TCP时可以不用考虑
至于“收到确认”完全不必要,为了对付连接断开,可以每个包都带序号,断开连接时,发送端重发未发送完的包
Fly1980 2003-09-23
  • 打赏
  • 举报
回复
youngwhz(sunbird) 说得非常对。

建议的解决方法:
将文件分块发送,接收端每收到一块数据就发送一个收到确认给发送方(包括收到的数据长度)
发送方在收到接收方发送的“收到确认”后才接着发送下一块数据。。。。
直到整个文件发送完毕。
每块数据都加一个包头,里面可以包含一些标志信息,如:是否所有数据发送完毕(即最后一个包了)
navy125 2003-09-23
  • 打赏
  • 举报
回复
应该说来是可以避免的,在发送端需要加入Select()选项,等待Select()返回后才会发送下一个包。
Select()作用判断当前网络是否可读或者可写,如果不可读或者不可写函数会被阻塞。

虽然这样可能会影响一些速度,但是一般不会造成堆栈溢出的。
加载更多回复(4)

4,356

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧