免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 10283 | 回复: 20
打印 上一主题 下一主题

write socket时的一个疑问 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-12-22 15:03 |只看该作者 |倒序浏览
10可用积分
想请教一下, 我有两台机器在通信, PC1, PC2, 当PC1要向PC2发送数据的时候, 我把PC2的网线断掉, 此时PC1在调用write()的时候, write()会成功返回, 并且返回写入内核的字节数, 但是PC1由于没有收到PC2的ACK包, 会一直重传, 并且在几分钟之后放弃发送数据.

此时如果做如下操作分别有如下对应的结果:

1. PC1继续write, 则write出错, 并且返回没有路由可到达的错误. 断掉socket
2. PC1在write之后就调用read, read会阻塞, 过一会儿read会返回和上面一样的错误,也是路由不可达的错误. 断掉socket.
3. PC1不再管这个socket了, 做其它的事情, 那么我观察了一下, 过了一会儿这个socket就断掉了. 对进程并没有什么影响.

这只是我实验的数据. 我看TCP/IP详解上面也只是讲了重传的算法, 并没有讲如何影响用户态程序的, UNP上也没有讲这种情况, 不知道各位以前对这个有没有什么研究吗?
那么平时编网络程序时应该如何来解决这种问题呢? 我现在也只是在应用层自己制定了一种协议, 即在write之后就调用read, 通过read的返回值来判断. 不知道各位还有没有什么其它的好方法?
望指教.
谢谢.

最佳答案

查看完整内容

TCP流可以保证快速.你发了1K, 等待确认, 那流量就受大影响了.设置超时, 不断发, 直到write出错或超过时间限制.这样可以充分利用TCP流的速度. 网络大部分时间是通的,断的时候是少数.例子,SMTP发送邮件就是如此. 你不能发1K,就等待回应, 确认后再发1K,... 那速度就十分慢了.SMTP发邮件内容时候,就是不断发, 直到最后发完,或出错误,或TIMEOUT. http://bbs.chinaunix.net/viewthread.php?tid=1024366&highlight=%CB%BC%D2%BB%BF%CB从北 ...

论坛徽章:
0
2 [报告]
发表于 2007-12-22 15:03 |只看该作者
TCP流可以保证快速.
你发了1K, 等待确认, 那流量就受大影响了.

设置超时, 不断发, 直到write出错或超过时间限制.
这样可以充分利用TCP流的速度.
网络大部分时间是通的,断的时候是少数.

例子,SMTP发送邮件就是如此. 你不能发1K,就等待回应, 确认后再发1K,... 那速度就十分慢了.
SMTP发邮件内容时候,就是不断发, 直到最后发完,或出错误,或TIMEOUT.



http://bbs.chinaunix.net/viewthr ... =%CB%BC%D2%BB%BF%CB

从北京到上海建立了集装箱货物运输线路.

北京是发送方,上海是接收方.
货物发送者将货物送到北京的货场. 运输公司将货物标记,装箱,然后配车往上海一箱一箱运.
货场的存货不多.

上海方面收到了箱,打电话告诉北京货场,某编号的箱已经收到了,并且打开箱根据标识重新分配货物,等货物接收者来取走.

如果运输路线桥断了,塞车了,

1)发送方不可能在第一时间知道,所以它还继续发. 一直塞到门口为止. 或者:
2)发送方一般知道一个箱子发车后最长多久一定可以收到上海的收到确认电话.比如一天.如果3天还没有,北京也可以确定路上出问题了.

这个类似于TCP STREAM SOCKET的工作过程.
有很多人问,为什么线路断了(比如网络线拔了)发送方还可以成功地send.
比喻不完全恰当,但说明道理.

论坛徽章:
0
3 [报告]
发表于 2007-12-22 15:21 |只看该作者
如果不显式的调用read write(或其他针对socket的操作函数)  应用程序应该不会得到提示

论坛徽章:
0
4 [报告]
发表于 2007-12-22 15:27 |只看该作者

回复 #2 cugb_cat 的帖子

嗯. 我得到的也是这样的结果, 那是不是一般在write之后都应该有一定的检测措施呢. 如read, write.
我写代码的经验不太多, 所以有些遇到的问题还很陌生.

论坛徽章:
0
5 [报告]
发表于 2007-12-22 15:28 |只看该作者
一般得,我的server端在accept每个clinent时保存一个时间,并且配置一个参数是处理每个连接最长的时间,这个时间一般是十几秒不会超过一分钟(当然也按照你的业务处理是否复杂而定),server端采用的IO复用模型,每次轮询的时候都会去查询当前时间与最开始接收到连接的时间差是不是超过了最大的范围,如果是的话就关闭socket,否则就一直保存这个连接在server端,当send出错时也关闭这个socket。

[ 本帖最后由 converse 于 2007-12-22 15:32 编辑 ]

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
6 [报告]
发表于 2007-12-22 15:33 |只看该作者
如果你是服务端的话..建议采用select 来轮循socket
如果是客户端的话..你发送了数据可以马上调用read 来进行同步地接收..也可以另起一个线程用 select来异步接收..

至于想判断socket 是否有效..你可以让客户端定时向服务端发跳消息..来维持这个连接..如果心跳超时,则认为失败.

论坛徽章:
0
7 [报告]
发表于 2007-12-22 15:51 |只看该作者

回复 #4 converse 的帖子

那你每次轮循的时候是不是会消耗很多的时间啊, 因为你每个client都要去判断一下. 还是每次select返回都只是查看当前描述符的时间?

论坛徽章:
0
8 [报告]
发表于 2007-12-22 15:55 |只看该作者
这里就是一个TCP连接的保活的过程,我觉得在不是很严格的情况下,在没有调用read或write时可以不关注这个socket的有效性,当read write调用出错了,再进行重连。

论坛徽章:
0
9 [报告]
发表于 2007-12-22 20:35 |只看该作者
原帖由 scutan 于 2007-12-22 15:03 发表
想请教一下, 我有两台机器在通信, PC1, PC2, 当PC1要向PC2发送数据的时候, 我把PC2的网线断掉, 此时PC1在调用write()的时候, write()会成功返回, 并且返回写入内核的字节数, 但是PC1由于没有收到PC2的ACK包, 会 ...


我没怎么看明白你的 问题, 给你点建议, 也许不是你的问题的 答案。

windows linux 还有部分 unix kernel已经提供了 tcp keepalive的 能力,

你只需要用 setsockopt 设置己个 arg就可以了  keepalive , keepidle, keepinternal .....

当条件满足的时候, kernel就会发 出一些probe tcp packet去帮你探测对方是否还活着。

如果对方死掉了, 会通知用户进程的。

论坛徽章:
0
10 [报告]
发表于 2007-12-22 20:53 |只看该作者

回复 #1 scutan 的帖子

楼主的做法是对的,应该用协议来确保socket 通信的完整性
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP