2007年8月17日星期五

udp----数据分包问题!

楼主lucbesson(女娃哈哈)2005-04-09 18:33:21 在 .NET技术 / C# 提问

udp有最大的数据传输控制,所以要进行分包处理。

1 把server中的bytes数组进行分割,并传输出去 ,该如何分包呢 ?
2 client端要如何接受呢 ?

---------------------------------------------------

//SERVER 发送数据
string str=this.richTextBox1.Text ;

byte[] bytes =Encoding.Unicode.GetBytes(str);

// **STEP 3**发送数据
udp.Send(bytes,bytes.Length );

// **STEP 4**关闭连接
udp.Close ();
-----------------------------------------------------

//CLIENT 接收数据
byte[] receiveBytes=receive.Receive(ref RemoteIpEndPoint);
string returnData=Encoding.Unicode.GetString(receiveBytes,0,receiveBytes.Length); 问题点数:80、回复次数:19Top

1 楼lucbesson(女娃哈哈)回复于 2005-04-09 18:37:50 得分 0

winform !!Top

2 楼hainang1234(海浪)回复于 2005-04-09 18:59:02 得分 0

ding....Top

3 楼lucbesson(女娃哈哈)回复于 2005-04-10 00:10:00 得分 0

先顶一下吧,有沉的趋势 。Top

4 楼Yamir2004(学习中..说错了别骂人,多指点..)回复于 2005-04-10 00:55:37 得分 0

我觉得最好给每个bytes做个标记
并且做传输是否成功的检查
如果没有传输成功就重新发送
ps:当然具体实现要比这个还要复杂点更好,用udp简单实现tcp传输的效果
这样比较好Top

5 楼diaoerlangdang()回复于 2005-04-10 08:26:30 得分 0

upTop

6 楼pc_csharp(帮助别人,帮助自己)回复于 2005-04-10 13:36:40 得分 0

在你QQ里
Top

7 楼Sunmast(速马@Redmond, WA)回复于 2005-04-10 17:25:24 得分 0

有个TFTP协议(Trivial File Transfer Protocol),用于在UDP上传送文件
自己做这个的话,数据包都得自己校验,是不是有点麻烦

有一些关于TFTP的LibraryTop

8 楼Yamir2004(学习中..说错了别骂人,多指点..)回复于 2005-04-11 01:20:12 得分 30

tcp协议简单理解可以认为是这样的
a --send--> b
a <--result- b
如果a没收到则重发
同理只要在每个传输的bytes里做好了标记
如果用udp一样可以做出这种效果
相当于是自己在udp的基础上定义了一个传输控制的协议吧
如果要再做好点,可以复杂点的,比如
每次控制几个bytes,例如控制4个bytes
先传输第一到第四个,如果第一个到达,控制区域就变为第二到第五个
..............一直推下去
当然这只是简单的实现了一点tcp的优势
实际上tcp协议肯定要比这复杂多了Top

9 楼Yamir2004(学习中..说错了别骂人,多指点..)回复于 2005-04-11 01:21:41 得分 0

byte都是十六进制的数字,拿来做标记还是很方便的:)Top

10 楼cnming(cnming)回复于 2005-04-11 08:30:00 得分 40

知道时间戳吗?如果知道的话就很好办

首先针对这个byte数组进行分成若干等份,并且按顺序在每个等份上打上一个序列号如果你的数据不是太长的话,放置一个字节即可,如果你的数据很长的话,放置两个字节即可。

发送方按照顺序发送
接收方如果接收到某一个系列号的数据包,则把这个系列号发送回到服务端,服务端接受到这个系列号的时候就可以对这个系列号所在的那个数据包进行销毁工作
如果服务器端没有接收到已经传送成功了的数据包系列号,则主动重发
如果服务器端接收到客户端要求重发的数据包系列号的时候,则重发
客户端接受到数据包之后就按系列号进行组织数据,并且去除系列号。
客户端针对没有接收到的数据包或者损坏的数据包,可以发送请求,要求服务器重发Top

11 楼Yamir2004(学习中..说错了别骂人,多指点..)回复于 2005-04-11 11:30:57 得分 0

同意楼上的
简单点就是把前两个字节拿来做标记
传输和组织数据的时候前两个只是用来做判断的
最好再标记一个结尾的标记,这个我觉得还是比较有用的:)
Top

12 楼qiezic(破晓)回复于 2005-04-11 11:59:31 得分 10

你可以每次从字符串中读出固定长度的字符,并用变量记录下下回读取字符的起始位置。
至于客户那边要接收并做处理,所以可以把从服务器发出来的包定义成一个类,类中包括该串字符的起始地址、结束地址和该串字符。当然在发送时要先把这个类序列化!
客户接收到包后就可以利用包中的信息重新拼出完整的串。Top

13 楼lucbesson(女娃哈哈)回复于 2005-04-12 00:11:32 得分 0

http://blog.china-pub.com/more.asp?name=immelman&id=11593

帮忙看看代码,有错误。
CLIENT 是个whlie控制的死循环的阻塞模式,怎么组合数据包呢 ?
Top

14 楼cnming(cnming)回复于 2005-04-12 08:17:06 得分 0

数据包一般是等分形式,如果按照我的方法,你只要按照获取的系列号进行换算就可以换算出你取回的数据包的位置了

UDP传输中,不见得会先传先到,所以需要打上一个戳Top

15 楼cnming(cnming)回复于 2005-04-12 08:20:26 得分 0

在启动传输的时候,服务器把数据整个进行分包,然后记录下分包信息,比如包的个数和数据包大小以及每一个分包的大小,传输给客户端

客户端如果获取了所有的分包数据,就说明已经完全获取了整个数据包,就可以直接退出循环。


Top

16 楼lucbesson(女娃哈哈)回复于 2005-04-12 16:51:34 得分 0

使用的是udp广播,还是个阻塞模式。

客户端如果获取了所有的分包数据,就说明已经完全获取了整个数据包,就可以直接退出循环。
这样好象不太容易 !Top

17 楼lucbesson(女娃哈哈)回复于 2005-04-12 16:56:04 得分 0

哪位朋友提供一个数据分包的项目,看一下。
学习学习

谢谢Top

18 楼cnming(cnming)回复于 2005-04-13 09:04:26 得分 0

题外话:广播会被好多的路由器拒绝


我这里也很忙,此外你的代码不齐全,所以很难调试


1、服务器端获取数据的总长
2、服务器端向客户端发送一个数据总长度,和即将发送的每一个数据包的长度
3、客户端向服务器端返回接收到服务器端发送的(2)的数据
4、服务器端开始向客户端发送数据包,并且启动针对这个数据包的TimeOut机制
5、客户端接收数据包
6、客户端向服务器端把接收到的数据戳,服务器端即可把这个数据销毁
7、如果服务器端在某一个数据包的TimeOut之后还没有接受到(6)的信息,则重发数据包,重复几次如果都失败就可以证明无法发送
8、重复4到7


戳 很简单,也就是在数据包前加上一个整数
例如有一个10500字节长度的数据,如果要把它分为每个1000字节长度的数据包,则可以分为11个,前10个每个1000字节,最后一个500字节,其实这个长度最好不要定死,这样你好根据网络情况进行设定长度
针对这个例子,你的戳就是0---10这11个数
可以把你的数据包的第一个字节作为记录这11个数的位置,这样你的数据长度就变成了1001字节。



Top

19 楼cnming(cnming)回复于 2005-04-13 09:13:16 得分 0

using System;
using System.Text;

namespace UDPTest
{
///
/// ClassEmployee 的摘要说明。
///

public class ClassData
{
public int m_intSN; //数据戳功能
public int m_intDataLength; //数据长度
public string m_strData; //数据内容

public ClassData()
{
}

//还原数据
public ClassData(byte[] data)
{
int place = 0;
m_intSN = BitConverter.ToInt32(data,place);
place += 4;
m_intDataLength = BitConverter.ToInt32(data,place);
place += 4;
m_strData = Encoding.ASCII.GetString(data,place,m_intDataLength);
}

//转换数据为字节数据
public byte[] GetBytes()
{
byte[] data = new byte[1024];
int place = 0;
Buffer.BlockCopy(BitConverter.GetBytes(m_intSN), 0, data,place,4);
place += 4;
Buffer.BlockCopy(BitConverter.GetBytes(m_intDataLength), 0, data,place,4);
place += 4;
Buffer.BlockCopy(Encoding.ASCII.GetBytes(m_strData), 0, data,place,m_strData.Length);
return data;
}

}
}

没有评论: