问题描述
我用udpclient发送数据,将数字拆分成若干个数组(每次发送的数据大小为:byte[1470])然后循环发送.发送8次以下没有问题。但是超过8次的数据量就接受不到了。最多只能接收到7个数据包。发送用的是udp.send();此发送没有用异步应该是没有问题的,8个包以下的数据量就没有问题。发送超过7次时接收到最多只有收到7个包。//接收数据的代码用的是udpClient的BeginReceive和EndReceive方法。不知道那里有问题。是不是udp或套接字对发送数据的次数有限制,还是代码不对,请大侠们指点下
解决方案
解决方案二:
该回复于2011-12-15 09:52:20被版主删除
解决方案三:
高手们冒个泡啊
解决方案四:
该回复于2011-12-15 09:53:12被版主删除
解决方案五:
你测试下数据小些,还是8个包看看什么效果
解决方案六:
该回复于2011-12-15 09:08:51被版主删除
解决方案七:
这个,个人感觉没有什么关系,除非是大数据量。调试跟踪一下,看看发送跟接收的数据是否一致,接收后分组操作是否正确,所有组的数据跟发送的作比较...
解决方案八:
引用6楼chenandczh的回复:
这个,个人感觉没有什么关系,除非是大数据量。调试跟踪一下,看看发送跟接收的数据是否一致,接收后分组操作是否正确,所有组的数据跟发送的作比较...
我能够确认发送是正确的,但是在接收的时候就是接收不到第7次和以后发送的数据,当我发送次数7次的总共数据量为:1470*7=10290个字节,此时我就接收不到第七个包了。10290数量很小啊,如果我不分包发送的话好像最多只能更够发送8192个字节吧
解决方案九:
这个是我发送的代码:publicvoidSendBySize(objectobj){lock(sendLock){LIS_Message.LisMessagemessage=(LIS_Message.LisMessage)obj;intPacketSize=1470;longsendSN=GetSendSN();Socketuc=newSocket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);uc.EnableBroadcast=true;uc.Connect("255.255.255.255",3729);MemoryStreamms=newMemoryStream();BinaryFormatterb=newBinaryFormatter();b.Serialize(ms,message);byte[]m_content=ms.ToArray();longMsLength=ms.Length;ms.Close();intsendLength=0;//已发送数据长度intLastPageSize=0;//最后一个包大小byte[]datas=newbyte[PacketSize];//声明字节数组intCurPackSize=0;//当前包大小//计算出总共需要分多少包才可以发送完一个消息intMaxPacketCount=(int)Math.Ceiling(double.Parse(MsLength.ToString())/double.Parse((PacketSize-28).ToString()));LastPageSize=(int)MsLength%(PacketSize-28)+28;//得到最后一个包的长度for(inti=0;i<MaxPacketCount;i++){if(i==MaxPacketCount-1){datas=newbyte[LastPageSize];CurPackSize=LastPageSize;}else{CurPackSize=PacketSize;datas=newbyte[PacketSize];}BitConverter.GetBytes(sendSN).CopyTo(datas,0);//消息编号0-8位BitConverter.GetBytes(i).CopyTo(datas,8);//此包体在消息的位置8-12BitConverter.GetBytes(MaxPacketCount).CopyTo(datas,12);//包个数12-16BitConverter.GetBytes(CurPackSize).CopyTo(datas,16);//当前包大小BitConverter.GetBytes(MsLength).CopyTo(datas,20);//消息总大小20-27if(i==MaxPacketCount-1){Array.Copy(m_content,sendLength,datas,28,CurPackSize-28);}else{Array.Copy(m_content,sendLength,datas,28,CurPackSize-28);}sendLength+=(CurPackSize-28);uc.Send(datas,SocketFlags.None);//发送}uc.Close();Thread.Sleep(5);}}
这个是我接收数据EndReceived的回调方法,这里无法接收到第7个以后的数据包:privatevoidgetMessage(objectobj){byte[]data=(byte[])obj;byte[]headSN=newbyte[8];byte[]sort=newbyte[4];byte[]PacketCount=newbyte[4];byte[]content=newbyte[data.Length-28];//byte[]packSize=newbyte[4];//当前包长度byte[]msLength=newbyte[8];try{Array.Copy(data,0,headSN,0,8);Array.Copy(data,8,sort,0,4);Array.Copy(data,12,PacketCount,0,4);Array.Copy(data,20,msLength,0,8);Array.Copy(data,28,content,0,data.Length-28);}catch(Exceptionex){MessageBox.Show("复制错误:"+ex.Message);}try{lock(thisLock){MessageTemptemp=newMessageTemp();temp.receiveTime=DateTime.Now;//获得包序号temp.SN=BitConverter.ToInt64(headSN,0);temp.sort=BitConverter.ToInt32(sort,0);temp.PacketCount=BitConverter.ToInt32(PacketCount,0);temp.Content=content;temp.messageSize=BitConverter.ToInt64(msLength,0);listTempData.Add(temp);if(temp.PacketCount==temp.sort+1)//最后一包{List<MessageTemp>M_list=listTempData.FindAll(newPredicate<MessageTemp>(delegate(MessageTempm){returnm.SN==temp.SN;}));M_list.Sort(newMessageSort());byte[]MessageContent=newbyte[temp.messageSize];intindex=0;for(inti=0;i<M_list.Count;i++){try{MessageTempt=M_list[i];Array.Copy(t.Content,0,MessageContent,index,t.Content.Length);index+=t.Content.Length;}catch(Exceptionex){stringe=ex.Message;stringa=e+"";}}for(inti=0;i<M_list.Count;i++){listTempData.Remove(M_list[i]);}System.IO.MemoryStreamms=newSystem.IO.MemoryStream(MessageContent,0,MessageContent.Length);BinaryFormatterb=newBinaryFormatter();LisMessagemessage=b.Deserialize(ms)asLisMessage;SOCKETEventArrive2(message);}}}catch(Exceptionex){MessageBox.Show("接收错误:"+ex.Message);}}
解决方案十:
缓存问题造成的,你发送太快,对方来不及接收,网卡缓存了7个包,之后的缓存里放不下就丢了。其实是你没有处理收发同步问题,TCP的三次握手自动处理了收发同步,但是UDP有没自动处理,发送方只管发,不管对方是否来得及收。必须每发送一个包,等待对方UDP返回一个确认包,也就是把三次握手变为了二次,同时不需要保持连接,速度自然比TCP快,但是要处理的细节比TCP多得多。
解决方案十一:
引用9楼qldsrx的回复:
缓存问题造成的,你发送太快,对方来不及接收,网卡缓存了7个包,之后的缓存里放不下就丢了。其实是你没有处理收发同步问题,TCP的三次握手自动处理了收发同步,但是UDP有没自动处理,发送方只管发,不管对方是否来得及收。必须每发送一个包,等待对方UDP返回一个确认包,也就是把三次握手变为了二次,同时不需要保持连接,速度自然比TCP快,但是要处理的细节比TCP多得多。
也就是说我在发送每一个包得时候需要等待对方发一个包回应,然后我再继续发下一个包?
解决方案十二:
当然了,不然你怎么知道对方已经接收?发送的时候不会自动等待对方接收,没这样的信号,只能程序中判断对方发回的响应包(包内数据少的话,基本不占带宽)。
解决方案十三:
引用11楼qldsrx的回复:
当然了,不然你怎么知道对方已经接收?发送的时候不会自动等待对方接收,没这样的信号,只能程序中判断对方发回的响应包(包内数据少的话,基本不占带宽)。
是的啊,我在每次send之后Sleep(50)就好了
解决方案十四:
引用11楼qldsrx的回复:
当然了,不然你怎么知道对方已经接收?发送的时候不会自动等待对方接收,没这样的信号,只能程序中判断对方发回的响应包(包内数据少的话,基本不占带宽)。
我是发送给所有的用户(255.255.255.255),能否发送给指定的几个ip?还是需要循环发送?
解决方案十五:
指定几个IP就需要循环发送了,不过发送所有用户是无法获取确认包,而指定IP就可以获取了另外测算下每个包大小和实际的带宽的话,按照每秒200KB的速度,那么200*1024/1470=139,也就是说,你控制200KB/S的速度发送的话,1秒内只能发送139个包,每个包需要的时间是1/139=0.007,大概每隔7毫秒就可以发送一次了。总之,先计算实际带宽可能的上限,然后推断安全的速度,不然UDP就很容易丢包了。
解决方案:
引用14楼qldsrx的回复:
指定几个IP就需要循环发送了,不过发送所有用户是无法获取确认包,而指定IP就可以获取了另外测算下每个包大小和实际的带宽的话,按照每秒200KB的速度,那么200*1024/1470=139,也就是说,你控制200KB/S的速度发送的话,1秒内只能发送139个包,每个包需要的时间是1/139=0.007,大概每隔7毫秒就可以发送一次了。总之,先计算实际带宽可能的上限,然后推断安全的速度……
对于接收数据我还是有个问题想请教下大哥:发送太快的时候,在接收的时候数据会不会合并到一个byte数组里?丢失包的原因我还是不确定,我接收的时候先处理接收到数据,处理完之后再去接收(beginReceive),类似于递归,如果发送的过快的话我还是接收不到数据。因为在处理接收时需要时间,而这段时间没有调用接收的方法?
解决方案:
这里有个文章很不错,建议你看看。这里面提到了UDP的包最大可以64K字节,如果你直接发送64K字节的UDP数据包,理论上也可以成功,在MTU上会自动拆包,到了接收端自动组装包,但是这个自动组装有个条件,就是要所有的碎片包都能收到才会组装,所以这里不确定因素很大,一旦丢了一个碎片包,整个大包都发送失败。所以一般都是自己拆成小于MTU的大小发送的。引用
EthernetMTUisusually1500bytes,butsomeconnections(suchasdial-upandsometunnelingprotocols)haveanMTUof1280bytes.Practicallyspeaking,itishardtodiscovertheminimumMTUofalink,sochoosingapacketsizeoflessthan1280(or1500)willincreasereliability.
至于你所说的是否会合并,那个答案很清楚了,如果发送方是分成小包发送的,接收方不会自动合并,如果发送方是一个大包,通过MTU自动拆包发送的,那么接收方就会合并。丢包除了发送过快,正常情况下也会出现,所以说UDP不安全,需要自己验证是否丢包,并重发所丢的包,这方面的技术知识,上面贴的链接里有示例代码,请自行研究。