socket接收并保存数据

sparrow429 2013-10-30 04:54:40
socket,UDP接收并保存数据有时候会丢包,每秒20k(1K一个数据包)
流程挺简单,接收到数据,数据放到类里面,里面对数据的判断,有数据头,长度,类型,还有校验(计算校验码比较),然后根据类型对数据进行处理,数据中有个总包号(一秒数据的总包号),一个当前包号,把同一秒的数据保存到ARRAYLIST中,总包号跟当前包号相等,就把当前的ARRAYLIST中的数据保存,再清空,接着保存下一秒的数据
保存方式用FileStream ,stream.Write()来保存
各位帮我诊断下,哪有问题>?
...全文
823 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
rtdb 2013-10-31
  • 打赏
  • 举报
回复
引用 5 楼 sparrow429 的回复:
但我进行了测试,如果光接收不保存的话,是不会丢包的
这说明在你处理数据时,有包到达没接收到。 可以考虑用多线程,一个线程只负责接收, 收到的包交给另一个线程处理。
yxjvbgood 2013-10-31
  • 打赏
  • 举报
回复
有可能是你代码处理的不正确,包数据到来时你的程序在占用,个人觉得UDP随然丢包,但那种机率还是很小的。而且不可能每次都丢包。
gomoku 2013-10-31
  • 打赏
  • 举报
回复
引用 5 楼 sparrow429 的回复:
但我进行了测试,如果光接收不保存的话,是不会丢包的
建议你阅读UDP百科等。设计上UDP是不可靠的,不能因为你几次的测试就认为它不不会丢包。 你可以设计一个数据结构来进行#4楼朋友说的掉包重发机制。 每个包的校验不太需要,因为UDP包本身有校验。 比如: 1、服务器发一个Rsp包,通知总共会有几个数据包,以及整个文件的MD5校验。 2、客户机进入接收模式(还可以通知服务器接收就绪)。 2、服务器开始发Data包,每秒200个等。 3、客户缓存接收到的Data包,并定时(比如每两秒)汇报接收状况,包括Ack和Nck包。 4、服务器重发客户没有收到的包,如果丢包率过高,降低传输速度。 5、客户凑齐所有包后,确认校验码,并发送Fin结束包,通知服务器以便清理缓存等。

public class Packet
{
    public enum PacketType : short
    {
        Rsp,      // 开始发送。Number为数据块总数,Data可以是16个字节的MD5。
        Ack,      // 确认收到。Number为数量,Data为int数组,每个元素为一个编号。
        Nak,      // 确认丢失。Number为数量,Data为int数组,每个元素为一个编号。
        Fin,      // 确认完成。Number为零,Data为空。
        Data,     // 传输数据。Number为编号,Data为数据。
    }

    public short Magic = 0x5566;
    public PacketType Type;
    public int Number;
    public byte[] Data;
}
Kenall 2013-10-31
  • 打赏
  • 举报
回复
接收数据后,开辟一个新的进程来处理写操作。 我猜测可能是你处理数据时候,端口被占用着,导致丢包
sparrow429 2013-10-31
  • 打赏
  • 举报
回复
但我进行了测试,如果光接收不保存的话,是不会丢包的
sparrow429 2013-10-31
  • 打赏
  • 举报
回复
引用 14 楼 sparrow429 的回复:
private void bwDoWork_EnvelopeData_DealWith(object sender, DoWorkEventArgs e) { while (true) { if (this.oriData.Count != 0)//oriData是ArrayList { Common.CommPackage pac = (Common.CommPackage)oriData[0]; int i = pac.GetCommndID(); string fileName = "c:\\oriEnvelopeData.bin"; FileStream stream = new FileStream(fileName, FileMode.Append | FileMode.OpenOrCreate, FileAccess.Write); int dataLength = pac.GetDataLength();//一数据包多少个的数据 stream.Write(pac.GetData(), 0, dataLength); stream.Flush(); stream.Close(); oriData.RemoveAt(0);//除去保存的第一个数据 } } } BackgroundWorker用while(true)这样有问题吗?
在while中添加个sleep(1)就可以了
sparrow429 2013-10-31
  • 打赏
  • 举报
回复
private void bwDoWork_EnvelopeData_DealWith(object sender, DoWorkEventArgs e) { while (true) { if (this.oriData.Count != 0)//oriData是ArrayList { Common.CommPackage pac = (Common.CommPackage)oriData[0]; int i = pac.GetCommndID(); string fileName = "c:\\oriEnvelopeData.bin"; FileStream stream = new FileStream(fileName, FileMode.Append | FileMode.OpenOrCreate, FileAccess.Write); int dataLength = pac.GetDataLength();//一数据包多少个的数据 stream.Write(pac.GetData(), 0, dataLength); stream.Flush(); stream.Close(); oriData.RemoveAt(0);//除去保存的第一个数据 } } } BackgroundWorker用while(true)这样有问题吗?
sparrow429 2013-10-31
  • 打赏
  • 举报
回复
现在用两个BackgroundWorker,一个用来接收,一个保存,软件就假死了?这是什么原因啊
chinaheart88 2013-10-31
  • 打赏
  • 举报
回复
学习,UDP很难。
wb_han 2013-10-31
  • 打赏
  • 举报
回复
如果数据太多,单线程解析确实影响接收包的速度,导致丢包。 楼上说的是一种最好最全的解决办法。 其实还有一种解决办法就是,自己根据包头的信息,故意抛弃掉部分包,在解析的频率达到3-5秒中只解析一次完整的数据包(并非一个包)
xian_wwq 2013-10-31
  • 打赏
  • 举报
回复
引用 5 楼 sparrow429 的回复:
但我进行了测试,如果光接收不保存的话,是不会丢包的
这已经说明问题了,就是接收后进行解析的过程不异步化, 对于接收是有影响的。 建议接收数据后直接保存,然后使用线程池或单独线程对数据进行解析。
iloli 2013-10-30
  • 打赏
  • 举报
回复
UDP 需要你自己在代码中做数据完整性检查和掉包重发机制哟
tcmakebest 2013-10-30
  • 打赏
  • 举报
回复
UDP不丢包的话,还要TCP干嘛,它就是这德性啊!
  • 打赏
  • 举报
回复
UDP丢包不是正常么
rtdb 2013-10-30
  • 打赏
  • 举报
回复
UDP是可以丢包的,若不想丢,换TCP

110,536

社区成员

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

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

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