C#Tcp网络编程 如何判断文件发送完毕?

itneste 2010-08-04 08:33:41
1.c#tcp网络编程中,当客户端连接服务器之后,服务器要根据客户端的请求做不同的几个步骤,没做完一个步骤就要向客户端发送一个结果(如果出错可以提示客户端出错位置),在客户端如何来接受信息呢?会不会所有信息都被一个networkstream.read全部读取出来呢?
2.客户端代码

NetworkStream ns = tc.GetStream();
FileStream fs = new FileStream(@"F:\C#.NET网络编程.pdf", FileMode.OpenOrCreate, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
int count = 0;
double size = 0;
byte[] b = new byte[2048];
while ((count = br.Read(b, 0, 2048)) > 0)
{
try
{
ns.Write(b, 0, count);
size += count;
ns.Flush();
}
catch
{
Console.WriteLine("服务器已关闭!发送字节数为:" + size);
return;
}
}
Console.WriteLine("发送:" + string.Format("{0:F}", size / 1024) + " KB");

Console.WriteLine("文件传输完毕!");
//ns.Close();
//fs.Close();
//br.Close();
//tc.Close();

服务器端读取客户端发送的文件的时候用while((count =ClientNs.Read(b, 0, 2048)) > 0),ClientNs为networkstream对象,现在问题就是:
如果我把客户端最后的四行代码注释起来,服务端就一直停在while这里,只有当我把后四行写上才可以,怎样可以在不关闭连接的情况下来让服务器知道所有的文件是否都发送完成?如果我发送完文件了,接着又给服务器发送了一条命令,服务器会不会把命令也当成文件内容了呢?(和第一个问题相似),
本人刚学习网络编程,又很多地方都不懂,望大虾们给予解答,谢谢~~~
...全文
929 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
hake303 2010-08-04
  • 打赏
  • 举报
回复
发送文件之前,先把文件以Byte[]方式进行拆分,并对每一个包进行包信息描述,如:
包总数+当前包索引+内容包
然后一个一个包的发送。接收包根据包总数和当前包,判断已全部接收完后,再将各内容包整合成一个完整的Byte[],最后,将这个字节数组转成文件方式生成
happyrain2010 2010-08-04
  • 打赏
  • 举报
回复
和服务器端约定好 发送个结束标识
itneste 2010-08-04
  • 打赏
  • 举报
回复
对于第二个问题,以下各楼都解答的很好,谢谢你们~~
[Quote= 4 楼 lianshaohua :]
[/Quote]
[Quote= 7 楼 lianshaohua :]
[/Quote]
[Quote= 9楼 lianshaohua :]
[/Quote]
[Quote=10 楼 lianshaohua :]
[/Quote]
[Quote= 13 楼 lianshaohua :]
[/Quote]
[Quote= 17 楼 lianshaohua :]
[/Quote]
[Quote= 19 楼 lianshaohua :]
[/Quote]
itneste 2010-08-04
  • 打赏
  • 举报
回复
第一个问题4楼已作出解释,
[Quote=引用 4 楼 shaowenjie 的回复:]

一次socket.receive()可以接收这次receive方法前的所有未被接收的服务端信息。

[/Quote]
现在我想问的是:
1.如何才能保证我对另一端发送的命令对方能给我作出正确的分析呢?如果对方一次读了我发送的两条命令,那总体的命令就会丢失一条,是不是需要根据消息的格式来判断一下呢?如果格式不符就要求发送端重发?

2.按照上面的思路来设计的话我必须有一个List来存放发送的命令,而且我必须发送一条命令就必须等待接收端的符合格式消息,如果符合就继续发送下一条,如果不符合就从list中取出上条命令发送,不知是不是这样啊?

大家有什么看法~~
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 lianshaohua 的回复:]

在发送前先对文件进行分包,分成多少包你告诉一下另一端,然后每发一包,另一端就会计数;最好把包号也带上;
[/Quote]
恩 也是一招,好~~
ztenv 2010-08-04
  • 打赏
  • 举报
回复
在发送前先对文件进行分包,分成多少包你告诉一下另一端,然后每发一包,另一端就会计数;最好把包号也带上;
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 xiaozhi_5638 的回复:]

这跟心跳检测没有关系

楼主应该问Socket怎样传输数据
这跟丢包、混包有关 每次在发送数据之前 都要把数据格式化固定格式的消息 如消息=消息类型+消息长度+消息内容
接收方 可以根据消息类型 及长度 来判断 数据是否接受完成

具体
参考
[/Quote]
谢谢 我也得定义一个自己的应用层协议
请叫我卷福 2010-08-04
  • 打赏
  • 举报
回复
这跟心跳检测没有关系

楼主应该问Socket怎样传输数据
这跟丢包、混包有关 每次在发送数据之前 都要把数据格式化固定格式的消息 如消息=消息类型+消息长度+消息内容
接收方 可以根据消息类型 及长度 来判断 数据是否接受完成

具体
参考
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 bobo71072740 的回复:]

心跳检测
[/Quote]
这里需要心跳检测吗?tcp是基于连接的呀~
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 zcfzcf001 的回复:]

首要的是:必须定义数据通讯的各种详细命令,来区分走那个过程那个步骤;
1、定义你要发送文件的结构体(套接字,唯一序号,名称、文件大小、格式)
2、服务端转发时将文件分很多若干小数据块传输定义每次发送包大小固定,最后一次可以小于固定大小数;
定义固定包发送的命令如tranErveryData,和最后包发送的命令tranLastData
3、客户端每次接收时都需要盘点是否接收完毕,当前……
[/Quote]

经典
谢谢你,思路很清晰了 谢谢
bobo71072740 2010-08-04
  • 打赏
  • 举报
回复
心跳检测
zcfzcf001 2010-08-04
  • 打赏
  • 举报
回复
首要的是:必须定义数据通讯的各种详细命令,来区分走那个过程那个步骤;
1、定义你要发送文件的结构体(套接字,唯一序号,名称、文件大小、格式)
2、服务端转发时将文件分很多若干小数据块传输定义每次发送包大小固定,最后一次可以小于固定大小数;
定义固定包发送的命令如tranErveryData,和最后包发送的命令tranLastData
3、客户端每次接收时都需要盘点是否接收完毕,当前包是否是固数;盘点是否接收全,否则让服务器方转发,
如果是最后一包,判断是否总体大小与文件大小相符,不相符重新发送;
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 7 楼:]

[/Quote]
[Quote=引用 8 楼:]

[/Quote]
[Quote=引用 9楼:]

[/Quote]
[Quote=引用 10 楼:]

[/Quote]
综楼上各层,
Tcp是没有消息边界的,必须自己加入边界和判断。

TO:chichenzhe,谢谢你,我只知道结果是这样的,但是不知原因,经你这么一说明白了。
TO:geaim 谢谢你,你让我换了另外一种思路~~
TO:(Baal) 谢谢你 你说的那种方法我试过,挺麻烦的。好,以后有问题还要问你啊~~
TO:(smielfox) 谢谢你 看来我只能添加边界了~~
jinxuliang 2010-08-04
  • 打赏
  • 举报
回复
在协议的包头:
添加:文件结构信息。用于客户端校验。
文件发送完毕:应该发送一个命令,告诉客户端已经完成。
chichenzhe 2010-08-04
  • 打赏
  • 举报
回复
为什么close通道 对方就知道发送完成了呢.

因为对方也不知道你什么时候发送完成.所以对方会循环去取你发送的数据,直到取到-1为止.而这个-1只有你去close之后才能达到效果
chichenzhe 2010-08-04
  • 打赏
  • 举报
回复
你应该是发完一次文件就断开连接吧.

这样的话 server在发完足够的数据之后 close 掉通道即可.


长连接如4楼所说,他刚做完个SOCKET的代码... 不懂问他...
哈哈潜伏哥 2010-08-04
  • 打赏
  • 举报
回复
在发送文件的第一包数据中应该包含文件的大小信息,服务器则根据文件的大小信息于获得的数据字节数来比较,以此判断文件是不是发送完成了。如果是发送多个文件还要在第一包中包含文件的个数等等有用的信息,这些信息是必须的,所以需要楼主自己去封装第一包的数据格式,并在服务器收到第一包的时候做相应的解析,从而知道文件名、大小(字节数)、文件个数等等。一己之见。
itneste 2010-08-04
  • 打赏
  • 举报
回复
itneste 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 shaowenjie 的回复:]

一次socket.receive()可以接收这次receive方法前的所有未被接收的服务端信息。


你可以不用networkstream用send receive的方式发送接收。和服务器组成心跳连接的方式。这样可以不断开的情况下一直保持连接


发送完文件,就发送一个结束标记。让你的服务端做一个SWITCH判断,如果有例如"/!#/"这样的标记就表示发送完成。这种规则完全可以自己定……
[/Quote]
心跳连接?这个google一下没结果啊,能不能给点资料?谢谢~~发送和接受命令我用的streamReader/writer,这个是不是可以保证命令的正确性呢?
shaowenjie 2010-08-04
  • 打赏
  • 举报
回复
一次socket.receive()可以接收这次receive方法前的所有未被接收的服务端信息。


你可以不用networkstream用send receive的方式发送接收。和服务器组成心跳连接的方式。这样可以不断开的情况下一直保持连接


发送完文件,就发送一个结束标记。让你的服务端做一个SWITCH判断,如果有例如"/!#/"这样的标记就表示发送完成。这种规则完全可以自己定制。
加载更多回复(3)

111,078

社区成员

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

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

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