Chinaunix

标题: TCP 编程问题 [打印本页]

作者: learntolinux    时间: 2009-05-23 11:41
标题: TCP 编程问题
最近在看TCP/IP ,有一个问题在书上没有找到答案,感谢高手们帮我解惑!!

通过一个例子来描述我的问题

send(socket, buf, 1000,0 ); 书上说内核将buf的内容全部拷贝到套接口的发送缓冲区,send 就返回 1000 , 在应用层,我们就认为此次发送成功。

然而,此时TCP可能并没有将buf的内容发送到对端。如果TCP(TCP只保证可靠的传输,但并不保证100% 送到)发送失败了,应用层也不会知道,这样岂不会误导应用层???
也就是说应用层如果想要知道对端应用层是否真正的收到了数据,还需要在应用层也做一次确认?????

谢谢指点!

[ 本帖最后由 learntolinux 于 2009-5-23 11:55 编辑 ]
作者: learntolinux    时间: 2009-05-23 11:54
自己顶
作者: xinglp    时间: 2009-05-23 11:56
是的.  所以有时候数据传输采取 "拉" 的方式 比如 HTTP
作者: cyg19860205    时间: 2009-05-23 12:04
TCP是面向连接的     ”三次握手“
作者: lenky0401    时间: 2009-05-23 12:14
这个不是应用程序层应该考虑的事情,TCP协议的可靠性会保证将这1000字节数据发送到对端。 一次发送失败会重传。
如果把他们纠缠在一起,的确没法理清楚。

就算按你说的“由应用层来确认”,应用层怎么来确认呢?看过那个经典的东西两边蓝军协商攻击中间白军的例子就知道根本就没有百分之百的保证完全可靠的确认协议。
所以,“应用层也做一次确认”就够了么?

我对TCP协议栈不熟,呵呵,说不上更细节的理由,期待其它人回答吧,。。。。
作者: lsupper    时间: 2009-05-23 12:29
TCP发送失败,就返回结果 -1了,你就再重发吧,关于TCP底层自己的,把缓冲区的发过去,是它自己解决,应用曾只要判断send的返回值吧
作者: learntolinux    时间: 2009-05-23 12:37
原帖由 lsupper 于 2009-5-23 12:29 发表
TCP发送失败,就返回结果 -1了,你就再重发吧,关于TCP底层自己的,把缓冲区的发过去,是它自己解决,应用曾只要判断send的返回值吧

关键是当次send 成功后,TCP 有可能 发送失败,也就是说我并不知道当次是不是数据真的发送到对端去了
作者: learntolinux    时间: 2009-05-23 12:39
原帖由 lenky0401 于 2009-5-23 12:14 发表
这个不是应用程序层应该考虑的事情,TCP协议的可靠性会保证将这1000字节数据发送到对端。

只保证可靠发送,但是并不保证送达

[ 本帖最后由 learntolinux 于 2009-5-23 12:40 编辑 ]
作者: benjiam    时间: 2009-05-23 13:48
红蓝军问题。 最后一次确认永远没办法确认是否成功送达

解决方案
1 应用层要自己设计协议来确认消息发送成功。
2 1问1答 1确认就可以了
作者: 吃烤鱼    时间: 2009-05-23 14:12
原帖由 learntolinux 于 2009-5-23 12:37 发表

关键是当次send 成功后,TCP 有可能 发送失败,也就是说我并不知道当次是不是数据真的发送到对端去了



tcp会重新发送,直到送达
作者: learntolinux    时间: 2009-05-23 15:04
原帖由 吃烤鱼 于 2009-5-23 14:12 发表



tcp会重新发送,直到送达

好像不是吧 , 重试的时间是有限制的 好像是4~10分钟吧
作者: learntolinux    时间: 2009-05-23 15:06
原帖由 benjiam 于 2009-5-23 13:48 发表
红蓝军问题。 最后一次确认永远没办法确认是否成功送达

解决方案
1 应用层要自己设计协议来确认消息发送成功。
2 1问1答 1确认就可以了

我也是这么想的,这也是我最不想看到的结果 !!!
作者: binbin_as    时间: 2009-05-24 21:44
标题: 回复 #1 learntolinux 的帖子
TCP握手和其他机制应该可以自己解决的吧,可以让接收端在完整收到数据后,发送一个小的响应包塞
              -------正在看TCP,不知道对不
作者: milowind    时间: 2009-05-24 21:59
具体有没有发送成功是传输层层(TCP协议层)关心的问题
作者: ideawu    时间: 2009-05-24 22:04
有个概念楼主可能理解错了. TCP和TCP socket并不是同一个东西. TCP socket是应用程序接口, 是对TCP的包装, 是用户(调用send发送字段流的程序)和底层TCP的中间层. TCP尝试保证数据确实正确地传到对端, 如果无法成功, 本端也能知道. 只是, 套接口层(socket)没有提供这样的接口, 不是TCP不提供.

[ 本帖最后由 ideawu 于 2009-5-24 22:10 编辑 ]
作者: ideawu    时间: 2009-05-24 22:08
应用程序
    |
套接口系统调用(read, write)
    |    进程
------系统调用-------
    |    内核
套接口系统调用实现
    |  函数调用
套接口层函数
/  |  \
-------------
TCP UDP ...
作者: benjiam    时间: 2009-05-24 22:46
其实 还是有很多细节没有仔细研究过

a<===> b 建立连接 3步握手完成

非阻塞模式
a send 100 字节

如果b 没有返回ack 包, 也不返回rst . a 机器的反应。 是返回100 还是阻塞?

返回是等待b 返回ack, 还是压入内核栈以后就返回。
作者: urapple    时间: 2009-05-25 08:30
标题: 回复 #8 learntolinux 的帖子
不对,阻塞方式tcp send如果返回成功,就是成功了,失败,基本上就是网络出问题了。别管什么发送缓冲还是应用程序。
tcp本身的send就有recv过程,只有收到确认,才会继续发送下面的数据,否则如果发送缓冲满,send就阻塞住了,不会返回,你的上层程序也会一直等待,直到发送缓冲腾出空间。只不过应用层没有看到。如果把这点否定,就没法再往下开发了。
非阻塞方式tcp send返回成功与否,可真是只是说有没有拷贝到发送缓冲里,所以,一般情况,网络程序刚开始都要设置发送缓冲和接收缓冲,把他们搞大,在搞大 ^_^
非阻塞的发送失败,就要判断下,到底是什么错误了,可能是正常错误,所以非阻塞发送一般都需要循环发送(在发送失败的时候)。
不过,无论阻塞,非阻塞,只要是tcp,他的send都有recv过程,这点毋庸置疑。
这是小弟以往开发网络程序的一点经验。要是不对,还是以tcp协议为准。呵呵。
作者: learntolinux    时间: 2009-05-25 09:11
原帖由 benjiam 于 2009-5-24 22:46 发表
其实 还是有很多细节没有仔细研究过

a b 建立连接 3步握手完成

非阻塞模式
a send 100 字节

如果b 没有返回ack 包, 也不返回rst . a 机器的反应。 是返回100 还是阻塞?

返回是等待b 返回ack, 还 ...


我看了一些资料,我理解的是 : 无论阻塞还是非阻塞,a send 100 字节, 压入栈就返回(资料上说拷贝到TCP缓存),这时 100自己有可能还在本端或是发到了对端但是对端还没有返回ack。如不对,请指正!  好像和楼上的观点部分相冲突,呵呵!!

[ 本帖最后由 learntolinux 于 2009-5-25 09:14 编辑 ]
作者: bobozhang    时间: 2009-05-25 09:17
原帖由 urapple 于 2009-5-25 08:30 发表
不对,阻塞方式tcp send如果返回成功,就是成功了,失败,基本上就是网络出问题了。别管什么发送缓冲还是应用程序。
tcp本身的send就有recv过程,只有收到确认,才会继续发送下面的数据,否则如果发送缓冲满, ...


我觉得有误,不管阻塞还是非阻塞,send或write成功都不代表对方的协议栈已经接收到了我们数据,也不代表我们的数据一定从网口发出去了。
作者: 思一克    时间: 2009-05-25 09:23
http://bbs3.chinaunix.net/thread-1453318-1-3.html

看这个。
作者: urapple    时间: 2009-05-25 10:48
标题: 回复 #20 bobozhang 的帖子
呵呵,小弟的意思是,是否接收到数据是tcp 内部实现的,如果你连这个也否定,也不敢肯定,那tcp这种socket通信,就没办法开发了。
所以小弟认为究成功后是否对方接收到,毫无意思。上层只需知道怎么判断成功,怎么判断出错就行了。
也就是判断send的返回值。socket程序关注点应该是在阻塞非阻塞两种状态,返回值的判断,有几种情况,他们代表什么,该怎么处理上。
至于是否对方收到,那是tcp的事情,不需管理。因为它是tcp,所以我们认为他会保证。要是把这个否定了,或者是不敢相信了,
建议就别用tcp了,直接从ip层或者udp来实现或重写一个让你自己觉得可以信任的你的所谓tcp。

[ 本帖最后由 urapple 于 2009-5-25 10:52 编辑 ]
作者: yuanchengjun    时间: 2009-05-25 11:27
好好看看tcp吧,
不是你想的那样,
作者: cwinex    时间: 2009-05-25 12:37
只要TCP连接不断,底层一定能帮你发送过去。
对于一个TCP连接,你发送完毕以后,要么要收回复,要么要继续发送,从不会什么都不做了吧。
因此TCP连接上的错误,一定能通过随后的read/write获知。
作者: waguju    时间: 2009-06-01 16:46
貌似有点深,学习。
作者: xman0017    时间: 2009-06-02 09:35
原帖由 cwinex 于 2009-5-25 12:37 发表
只要TCP连接不断,底层一定能帮你发送过去。
对于一个TCP连接,你发送完毕以后,要么要收回复,要么要继续发送,从不会什么都不做了吧。
因此TCP连接上的错误,一定能通过随后的read/write获知。


同意,

send调用成功,表示发送数据任务已经成功交于系统了,

至于系统最后是否成功,要看当时情况了,

TCP SOCKET在协议上、原则上是可靠的(在当时环境正常情况下),

在说,即使有错误,后续read/write时应该会知道的。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2