再议议socket文件传输的机制.
C/S(都是自己写的服务器和客户端)下用socket传输文件不是什么新鲜的东西,
但是我想做好做稳定也不是件容易的事情,其中我想最重要的事情应该就是所采用的传输机制。
我现在准备写一个,想写的好点,所以有一些问题请教请教各位:)
1.分包的大小。
分包应该分多大才合适?我原来分的是512个字节,局域网没有问题。不过在internet上或者网络环境
很差的时候恐怕就不行了。所以现在想的方法是,先测一下速度,快的则用大包,慢的则用小包。不知道是否可行。还有大家一般怎么测速?
2.收每包的数据是否需要确认
无论是客户端收文件还是服务器收文件,都存在一个问题,就是收到一个包文件数据后是否要向发送方返回收到信息。我原来写的是没有的,局域网也没有问题,发送方稍微发慢点就可以了。现在想想感觉还是应该加上更合理些,不知道大家这块怎么做的
3.异常处理
异常的情况有很多,如通讯突然中断,但这两个情况我感觉比较复杂:
网络环境由好变差,之前定的分包肯定不合适了
客户端的暂停和继续,暂停时间长了,可能连接已经被服务器关闭了。
问题点数:100、回复次数:42Top
1 楼shadowstar(CodeFast for Delphi & C++Builder)回复于 2005-11-10 22:49:44 得分 30
1、TCP是以流的方式传输,所以不用考虑分包的大小,即使考虑实际传输未必是你想像的那样
2、TCP是一种可靠的传输协议,它已经完成了确认包的收到和重传错误的封包
3、如上所述,当TCP没有收到数据包确认应答时会socket API返回错误,也就可以处理异常了Top
2 楼pp616(坏蛋)回复于 2005-11-10 23:00:26 得分 10
1一般用2-4K
2最好是回一条消息。tcp是不会丢包。但是如果发送放发的太快而接收放来不急处理就会丢失数据。
3。可以在程序内部计算速度。如过越来越慢可以适当减小包的大小。如果速度恒定可以适当增大。
在被动放保存发送状态,遇到网络中断可以重新由断点出继续。
Top
3 楼pp616(坏蛋)回复于 2005-11-10 23:24:08 得分 0
http://www33.websamba.com/csdnpp616/send.rar
http://www33.websamba.com/csdnpp616/accept.rar
这是一个以前用bc写的一个文件传输的工具。支持多线程,支持断点继续传。传输速度在公网上基本可以达到连接速度。
楼主有兴趣可以试试。Top
4 楼woshialber(吴斐)回复于 2005-11-11 00:49:03 得分 0
哈哈,谢谢各位指点阿,还有代码,
明天再大概说说我的进展^_^Top
5 楼woshialber(吴斐)回复于 2005-11-11 00:52:52 得分 0
阿,不是程序阿:(。
呵呵,只好自己研究了:)
TCP的确是不丢包
但是好像会出现重组现象阿
比如clientsocket.send一个包
接受端可能是分两次收到的。Top
6 楼shadowstar(CodeFast for Delphi & C++Builder)回复于 2005-11-11 01:19:23 得分 0
to pp616(傻小子)
TCP的设计者在哭啊~~~Top
7 楼woshialber(吴斐)回复于 2005-11-11 08:54:21 得分 0
看来还有很多问题值得研究阿Top
8 楼netsys2(来电!)回复于 2005-11-11 09:51:55 得分 5
1) 分包的大小
512太小了,缺省情况下系统的SOCKET缓冲是8K,你每次传2-4K
2)收每包的数据是否需要确认
虽然会影响到速率,不过它能够保证你正确的传输和接收,如果对数据要求高,那么还是加上
3)异常处理
只要有第2条,就自动解决了,只要对协议增加一点点内容,你还可以做断点续传。Top
9 楼tompkins2000(AirHunter)回复于 2005-11-11 10:48:27 得分 0
偶也学习一下Top
10 楼shadowstar(CodeFast for Delphi & C++Builder)回复于 2005-11-11 13:31:28 得分 5
不要那么复杂吧?
1、
do {
bytes_sent = send(s, buf, len, 0);
buf += bytes_sent;
len -= bytes_sent;
} while (bytes_sent = 0 || bytes_sent = SOCKET_ERROR);
2、3、
如果需要确认的话建议使用UDP,用TCP再确认,完全是浪费,要确认还不如加密传输。Top
11 楼jixiaoqiang(探索者)回复于 2005-11-11 15:26:16 得分 5
传送文件是有问题的,前几天我刚作过。
比如发送文件之前要通知接收方我发送的文件名字,然后再发送文件。
我写的时候用的是vb,而VB是没有Flush缓冲区的功能的,至于CB我还没有试过,但我想应该都有这样的问题
单单发送一个文件是比较简单的,也不会出什么问题,但是如果多个文件,问题就出来了,听我给你讲:
当你第一个文件发完之后,你如果要发第二个文件,你得先发个文件名给接收方吧,如果你第一个文件的最后一次发送缓冲区不满8K的话,你发第二个的文件名将会随着你第一个文件的最后一批数据过去,你接收方根本就没法判断,这样会导致你第一个文件写的时候会多字节,第二个文件会少数据。
想通过中间休眠一段时间再发的话也行不通。
最后我只有发送文件名的同时发送文件的长度,服务器方检测是否接收超长,如果超长就截取。然后发送下一个命令,然后发送方再发送下一个。
再次声明,我用的是VB写的,仅供参考,请不要攻击.
Top
12 楼jixiaoqiang(探索者)回复于 2005-11-11 15:31:48 得分 0
另外还要注意的问题就是:
如果客户端、服务器端有通讯指令的话,服务器端要识别,不能将其写入文件。其他的数据默认就是文件的数据,全部写入文件。
否则写入的文件就不对了.
Top
13 楼woshialber(吴斐)回复于 2005-11-11 17:06:54 得分 0
jixiaoqiang(探索者)所提出的的确是个问题,不过是上层问题,而且还是比较好解决的。
看来大家也有几个分歧阿:
这段代码,我基本同意
do {
bytes_sent = send(s, buf, len, 0);
buf += bytes_sent;
len -= bytes_sent;
} while (bytes_sent == 0 || bytes_sent == SOCKET_ERROR);
但接受端是比较复杂,
一个包可能被分成几个包发了过来,也有可能是几个包组成了一个包发了过来
还有可能是前一个包和后一个包重叠问题。不过还好,这些都通过自定义的协议
进行拆包组报就以解决。
现在我想问的是用什么样的一个机制才能在各种网络环境下实现较稳定和较快速的文件传输。Top
14 楼shadowstar(CodeFast for Delphi & C++Builder)回复于 2005-11-11 17:23:36 得分 0
不好意思,代码应该是
while not ...
只是说明一下原理。
不要想得太复杂了,想想internet发展了多少年了,在它上面的协议难道没有合适的?Top
15 楼EagleFew(死牛之祭)回复于 2005-11-12 16:14:07 得分 10
我想也是 如果是TCP 传输的话,应该可以不用确认机制.例如 在cb 中使用流来发送,它就没有人为的加入确认机制,TCP协议本身就提供了,否则将出现接收端的接收数据的错误(发送速度大于读取速度).
我自己也写了一个文件传输的小程序:
用TCP控件写的,我加入了简单的确认机制,不过是使用组合的字符串形式的,不是发送的确认字符.
在局域网内能正常传输.速度比较快,但是internet就有点问题 ,经常出现问题:
传输机制:
1.使用SendBuf 发送文件
2.使用RecieveBuf 接收文件
3.请求接收字符串包括(文件名,文件大小,本机IP地址)
4.接收端用LeftSize(初始为零) 判断是否接收文件,该值在接收到发送端的发送请求后赋值
5.接收端确认文件已发送结束机制: 当缓冲区接收到的长度4k时,文件发送结束.
6.发送断确认文件已发送结束机制: 当LeftSize < 0 时确定发送结束.
7.发送端在发送一个数据包后等待接收端的请求发送文件字符串后再发送一个数据包
直至文件发送结束.
出现的问题:
1. 在网络速度慢的时候,达不到4k 的情况下,发送4k的数据包,接收端是否是分段接收的.
2. 有时候会出现不能接收数据的问题,就是不能连接.
错误机制:
接收端或发送端主动断开连接 给出提示,并且所有参数复位.
其它的没有考虑.
如果使用动态的数据包大小发送这样我认为可行.
另请教,如何解决超时的问题.在多少秒内没有接收到一个新的数据包接收端就发送一个请求发送文件的命令.
Top
16 楼Yans(跟贴是一种友谊)回复于 2005-11-14 13:46:45 得分 5
1、网络通讯分包是否太小了?怎么和我串口分的差不多呢?我以前考虑过一个
自动适应的通讯方式(串口),就是最先按通道质量最好的时候确定分包大小,如4K,
如果发送端连续发送3(可以自己定义)次,对方均未收到,则分包改为2K,依此类推。
还有种通讯方式:就是把一个大数据包分成很多个小数据包,每个包的大小可以为
512字节,甚至更小。每个小包都校验。接收方接收到数据后,每个小包都校验,将
未校验对的分包包号返回至发送端,请求重发。
不知这2种方法对楼主有帮助没?
哪位大虾有现成的基于Tcp/ip协议的用api做的cb通讯代码,贴出来大家测试测试阿!
Top
17 楼chris_crow(怀孕了,就别再来找我...)回复于 2005-11-14 14:38:30 得分 0
研究研究....Top
18 楼wenyongjie(我们的目标是:没有蛀牙!!)回复于 2005-11-15 15:15:54 得分 0
研究研究....
Top
19 楼pp616(坏蛋)回复于 2005-11-15 18:18:20 得分 0
正在整理代码。写好注册发出来供大家参考。Top
20 楼pp616(坏蛋)回复于 2005-11-15 18:31:16 得分 0
注释不是注册:)Top
21 楼wenyongjie(我们的目标是:没有蛀牙!!)回复于 2005-11-15 22:45:35 得分 0
支持pp616(傻小子)Top
22 楼yy2001()回复于 2005-11-16 09:06:52 得分 0
学习Top
23 楼sydt(亲情六处)回复于 2005-11-16 10:36:38 得分 0
支持pp616(傻小子)写好注释发出来供大家参考。
期待!!!
Top
24 楼titan_ysl(泰坦)回复于 2005-11-16 13:03:48 得分 0
支持pp616(傻小子)写好注释发出来供大家参考。
用了pp616(傻小子)的,很好的。想学学怎样使用Socks代理。
Top
25 楼woshialber(吴斐)回复于 2005-11-16 20:25:46 得分 0
呵呵,好!Top
26 楼woshialber(吴斐)回复于 2005-11-21 11:54:35 得分 0
还没有整理出俩??
期待啊Top
27 楼Yans(跟贴是一种友谊)回复于 2005-11-24 11:05:01 得分 0
需不需要校验呢?如果发送过去的数据发生错误该怎么处理呢?Top
28 楼Yans(跟贴是一种友谊)回复于 2005-11-28 11:31:20 得分 0
支持pp616(傻小子)
Top
29 楼ylc8131(大蚂蚁)回复于 2005-11-28 16:18:23 得分 5
tcp本身就能处理丢包(累计确认),发送接受方速度匹配(接受窗口),网络情况适应(拥塞窗口),包失序等情况,不用自己来搞...Top
30 楼kanshu123(初学者)回复于 2005-12-01 14:14:09 得分 0
pp616(傻小子) 2005-11-15 18:18:00
正在整理代码。写好注册发出来供大家参考。
还没有整理好吗?Top
31 楼panlsh(入门)回复于 2005-12-01 21:17:38 得分 0
新手,学习学习!Top
32 楼DelphiGuy()回复于 2005-12-01 21:50:56 得分 5
不是有FTP(本身就是基于TCP/UDP的)嘛,为什么还要自己在TCP上另起炉灶?
Top
33 楼woshialber(吴斐)回复于 2005-12-03 10:30:39 得分 0
>>tcp本身就能处理丢包(累计确认),发送接受方速度匹配(接受窗口),网络情况适应(拥塞窗口),包失
>>序等情况,不用自己来搞...
的确是这样,但网络环境的差异性很大,一套好的传输机制很重要。Top
34 楼woshialber(吴斐)回复于 2005-12-04 17:05:58 得分 0
对了,谁来说说FTP是如何做的?Top
35 楼DelphiGuy()回复于 2005-12-04 17:14:19 得分 5
就用Indy的FTP组件在程序中开一个FTP Server,把要传的文件链接发给对方,他一点接受就开始下载了。就象MSN Messenger中的发送文件一样。
一点也不复杂,1~2个小时就可以完成得象模象样的。:)
Top
36 楼sunxiaohui(sunxiaohui)回复于 2005-12-05 13:40:12 得分 5
建议如下:
1、要有包回应,便于验证数据。
2、包的大小,可以大一些,但不要大于1400,网络传输中,有一个值“最大传输单元”,一般为1500,考虑到在组包时,系统会自动增加一些内容,如目的地址、源地址、MAC地址等信息,如最后的发送包超过1500,则系统会进行分片发送。可以采取每次发送一定的数据,在服务器返回信息后,在发下一个数据包。同时,如果包太小,则线路利用率低,速度慢!Top
37 楼fkeumtdh(都4年多了,还是小三角-_-!)回复于 2005-12-05 16:04:08 得分 0
学习Top
38 楼woshialber(吴斐)回复于 2005-12-09 10:25:55 得分 0
呵呵,还是最后解决了一些问题。明天结贴:)Top
39 楼rudolf_he()回复于 2005-12-09 16:21:44 得分 5
介绍一篇文章给你
ftp协议实现多线程断点续传
http://www.vckbase.com/document/viewdoc/?id=1387
感觉还不错。
Top
40 楼web2003(卫兵)回复于 2005-12-11 10:29:56 得分 0
学习!
等待傻小子的作品。Top
41 楼Yans(跟贴是一种友谊)回复于 2005-12-13 16:52:39 得分 5
这里有个简单例子:http://www.csdn.net/develop/read_article.asp?id=19883
大家来看看,测试测试,能不能在这个上做出一个比较好的通用的类?Top
42 楼woshialber(吴斐)回复于 2005-12-17 01:38:16 得分 0
通过交流,学到很多东西,谢谢大家,分不是很多,不好意思:)
还有就是希望以后高手和大虾们能够尽量完成自己的承诺,不能完成的最好也能给给说明,免得大家等的干着急,赫赫。
//---------------------------------------------
Top




