socket接收文件问题,文件的发送方发送格式固定,没有文件长度。我应该如何接收文件?

scailin 2015-01-09 09:53:47
最近做一个socket通信的,现在已经有的TCP服务器端能够发送文件,但是发送文件的格式固定,只有文件名与文件数据。现在我应该如何接收这个文件,如何while循环去receive的话会阻塞,用异步beginread的话就会无限循环,我需要接收完数据就退出,所以这个办法也不行。我socket开发也有一段时间,自定义协议我是懂的,但是这次文件发送方无法提供文件长度,该如何接收?求大神指教。
...全文
241 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
SPFarmer 2015-01-09
  • 打赏
  • 举报
回复
引用 8 楼 sp1234 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
正规实用的通讯程序没有这样写的,这样的程序我只在某培训班的坑爹视频上见过。 一次 handler.Receive(bytes) 得到的是任意“截断的数据包”,你怎可以“既不管之前包、也不管之后的包”就随便取一小段数据就胡乱执行 Encoding.GetString() ?[/quote] 这个例子是MSDN的入门级例子,在纯英文的环境下是可以的,能得到字符串。 当然我也不建议这么做。我不建议转成string,而是直接使用byte。
  • 打赏
  • 举报
回复
引用 1 楼 SPFarm 的回复:
可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我看了一下这里引用的 msdn 的文档,msdn写的真的很坑爹。 这只有在单机或者非常好、没有干扰的局域网里测试才会能保证这样不出bug。凡是有一定经验的人都知道tcp会自动分包、自动粘包的。所以 msdn 的此类文档是有 bug 的。
scailin 2015-01-09
  • 打赏
  • 举报
回复
应该是不行了,没有文件长度,没有文件结束符,还是谢谢各位了。
於黾 2015-01-09
  • 打赏
  • 举报
回复
你要求对方发送文件,对方就胡乱的把文件名和文件内容发过来,这根本不能称为"协议" 估计对方也根本没做过通信 而且你还提到了是通过串口发送的 通过串口发送,就必须在协议里指定校验(sum校验,CRC校验等) 因为串口数据不保证准确性,需要自己加校验判断准确性(而TCP协议里底层已经封装好了校验的办法,校验不通过包就直接被丢弃了,不用你自己操心数据是否可能有错误) 比如串口线附近有个电机(强电磁干扰),很可能你收到的数据全部是0xFF这种东西
  • 打赏
  • 举报
回复
你自己都说了“当发送方发送第二个文件时,我检测到第二个文件头我才能确定....”,请问这是对方给你的白纸黑字的写出来的通讯规范吗? 如果是,那么你就只能这样编程。如果你一个劲抱怨说你是这样瞎猜的,那么你为什么不要对方给你白纸黑字地写上一条规范、明白告知“如何判断文件结束?”的问题?
於黾 2015-01-09
  • 打赏
  • 举报
回复
让发送方提供一个接收文件的demo给你,只知道"格式"其实不算是完整的协议 如果他们自己随便造的协议,自己都没想好该怎么接收的话,告诉他们修改协议
  • 打赏
  • 举报
回复
引用 10 楼 scailin 的回复:
发送方发的格式我是知道的,只有文件名和文件数据,具体协议格式我知道,没有文件长度。我之前编了一个异步的,之所以无限循环就是因为没有办法判断结束条件,当发送方发送第二个文件时,我检测到第二个文件头我才能确定第一个文件接收完整。
唉!你连发送数据结束时用什么来表示都说不出来。是不是对方跟你一样懒得跟其它相关编程者真正写明白必须的问题啊?
  • 打赏
  • 举报
回复
如果对方的规范文档中确实白纸黑字写着“以 ASCII 编码的5个字母‘<EOF>’表示文件结束",那么这种混乱的描述,你反而需要问几个问题: 1. 其它文字内容也是 ASCII编码吗?(这其实在中国是不太可能的) 2. 到底是这5个字符在”最后位置“表示文件结束?还是只要包含这5个字符在任意位置就表示文件结束?(这也有些荒诞的) 3. 这5个字符连带之后的文字,是否需要除掉?(这是必须知道的) 4. ...........文件名等等其它信息的结构在哪里规范?.......... 其实根本不太可能这样设计。如果对方给你的规范是这样的,你应该贴出规范文本来让别人给你看看。 不要自己胡乱发明什么代码,应该看对方给你的规范说明,写代码应该经得起推敲。
scailin 2015-01-09
  • 打赏
  • 举报
回复
引用 7 楼 sp1234 的回复:
[quote=引用 楼主 scailin 的回复:] 最近做一个socket通信的,现在已经有的TCP服务器端能够发送文件,但是发送文件的格式固定,只有文件名与文件数据。现在我应该如何接收这个文件,如何while循环去receive的话会阻塞,用异步beginread的话就会无限循环,我需要接收完数据就退出,所以这个办法也不行。我socket开发也有一段时间,自定义协议我是懂的,但是这次文件发送方无法提供文件长度,该如何接收?求大神指教。
1. 对方应该有规范的文档给你吧。难道你仅靠猜测来写程序? 2. 如果有规范的文档知道何时结束(哪怕是对方Close信道算是结束),那么跟异步就没有关系,就不存在什么“无限循环”的问题。这个“无限循环”的说法还是证明了你根本没有按照对方给你的协议规范来编程。 3. 你只是表白说你懂“自定义协议”没有什么意义,协议对方要给你的,不是你自己随便编的。 [/quote]
引用 7 楼 sp1234 的回复:
[quote=引用 楼主 scailin 的回复:] 最近做一个socket通信的,现在已经有的TCP服务器端能够发送文件,但是发送文件的格式固定,只有文件名与文件数据。现在我应该如何接收这个文件,如何while循环去receive的话会阻塞,用异步beginread的话就会无限循环,我需要接收完数据就退出,所以这个办法也不行。我socket开发也有一段时间,自定义协议我是懂的,但是这次文件发送方无法提供文件长度,该如何接收?求大神指教。
1. 对方应该有规范的文档给你吧。难道你仅靠猜测来写程序? 2. 如果有规范的文档知道何时结束(哪怕是对方Close信道算是结束),那么跟异步就没有关系,就不存在什么“无限循环”的问题。这个“无限循环”的说法还是证明了你根本没有按照对方给你的协议规范来编程。 3. 你只是表白说你懂“自定义协议”没有什么意义,协议对方要给你的,不是你自己随便编的。 [/quote] 发送方发的格式我是知道的,只有文件名和文件数据,具体协议格式我知道,没有文件长度。我之前编了一个异步的,之所以无限循环就是因为没有办法判断结束条件,当发送方发送第二个文件时,我检测到第二个文件头我才能确定第一个文件接收完整。
scailin 2015-01-09
  • 打赏
  • 举报
回复
引用 5 楼 SPFarm 的回复:
[quote=引用 3 楼 scailin 的回复:] [quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quote]这个
引用 3 楼 scailin 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quot
引用 3 楼 scailin 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quote] 这个只是一个例子,例子里面把接收的byte数组转化成了string。但是楼主接收的是文件内容,因此不需要这么写。直接用FileStream把byte写到磁盘上。 至于跳出条件,bytesRec ==0的时候,就可以跳出了。[/quote] 你的代码bytesRec永远也不会等于0,因为receive会阻塞了。之前我socket编程都是自定义协议的。你说的这个我懂的,现在我测试的关键有没有文件结束符传过来,有的话就好了,直接结束,跳出循环。
  • 打赏
  • 举报
回复
引用 1 楼 SPFarm 的回复:
可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
正规实用的通讯程序没有这样写的,这样的程序我只在某培训班的坑爹视频上见过。 一次 handler.Receive(bytes) 得到的是任意“截断的数据包”,你怎可以“既不管之前包、也不管之后的包”就随便取一小段数据就胡乱执行 Encoding.GetString() ?
  • 打赏
  • 举报
回复
引用 楼主 scailin 的回复:
最近做一个socket通信的,现在已经有的TCP服务器端能够发送文件,但是发送文件的格式固定,只有文件名与文件数据。现在我应该如何接收这个文件,如何while循环去receive的话会阻塞,用异步beginread的话就会无限循环,我需要接收完数据就退出,所以这个办法也不行。我socket开发也有一段时间,自定义协议我是懂的,但是这次文件发送方无法提供文件长度,该如何接收?求大神指教。
1. 对方应该有规范的文档给你吧。难道你仅靠猜测来写程序? 2. 如果有规范的文档知道何时结束(哪怕是对方Close信道算是结束),那么跟异步就没有关系,就不存在什么“无限循环”的问题。这个“无限循环”的说法还是证明了你根本没有按照对方给你的协议规范来编程。 3. 你只是表白说你懂“自定义协议”没有什么意义,协议对方要给你的,不是你自己随便编的。
於黾 2015-01-09
  • 打赏
  • 举报
回复
引用 4 楼 scailin 的回复:
[quote=引用 2 楼 Z65443344 的回复:] 接收的时候设置ReadTimeout参数(超时时间) 用while循环接收,并把接收的代码用try,catch包住 如果超时则进入catch(跳出循环)
这个我也想过,但是这个文件大小不一。期间串口转网口,传输速度决定于串口的波特率,文件传输慢,一个1M的文件9600的波特率要传十几分钟,ReadTimeout想过应该不好实现。[/quote] 跟传输速率快慢没关系 只要对方是连续发送的,你就应该能在超时时间到达之前接收到下一个数据包. 除非对方把包拆开,每隔5秒给你发送一个,那你还真没办法了
SPFarmer 2015-01-09
  • 打赏
  • 举报
回复
引用 3 楼 scailin 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quote]这个
引用 3 楼 scailin 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quot
引用 3 楼 scailin 的回复:
[quote=引用 1 楼 SPFarm 的回复:] 可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!![/quote] 这个只是一个例子,例子里面把接收的byte数组转化成了string。但是楼主接收的是文件内容,因此不需要这么写。直接用FileStream把byte写到磁盘上。 至于跳出条件,bytesRec ==0的时候,就可以跳出了。
scailin 2015-01-09
  • 打赏
  • 举报
回复
引用 2 楼 Z65443344 的回复:
接收的时候设置ReadTimeout参数(超时时间) 用while循环接收,并把接收的代码用try,catch包住 如果超时则进入catch(跳出循环)
这个我也想过,但是这个文件大小不一。期间串口转网口,传输速度决定于串口的波特率,文件传输慢,一个1M的文件9600的波特率要传十几分钟,ReadTimeout想过应该不好实现。
scailin 2015-01-09
  • 打赏
  • 举报
回复
引用 1 楼 SPFarm 的回复:
可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }
我正在试,<EOF>应该是文件结束符吧,我看过文件发过来的数据,结尾好像没有把这个发过来。我试试看,非常感谢!!
於黾 2015-01-09
  • 打赏
  • 举报
回复
接收的时候设置ReadTimeout参数(超时时间) 用while循环接收,并把接收的代码用try,catch包住 如果超时则进入catch(跳出循环)
SPFarmer 2015-01-09
  • 打赏
  • 举报
回复
可以参考一下 http://msdn.microsoft.com/en-us/library/6y0e13d3(v=vs.110).aspx while (true) { //因为不知道文件内容的长度,所以要用 while循环,不断的接取数据 bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); data += Encoding.ASCII.GetString(bytes,0,bytesRec); if (data.IndexOf("<EOF>") > -1) { // 接收完毕,跳出 break; } }

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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