巨大的问题------------udp数据报,分包的组合 !

lucbesson 2005-04-20 12:13:42
发送数据:

private void send()
{

// **STEP 1**创建一个UdpClient实例
udp= new UdpClient();

ip=IPAddress.Parse("192.168.1.255");
endpoint=new IPEndPoint(ip,serverport);

try
{
udp.Connect(endpoint);

string str=this.richTextBox1.Text ;
byte[] bytes =Encoding.Unicode.GetBytes(str);
//总包的大小
int totalSize=bytes.Length;
//***********小于mtu的数据包做标记直接发送****************
//如果总包超过udp的最大传输自己即MTU,则进行分包
if(totalSize<60000)
{ //数据小于60000字节,进行标记,方便Client接收
byte[] b1=new byte[totalSize+1];
b1[0]=1;
//给小于MTU的数据包做标记
Array.Copy(bytes,0,b1,1,totalSize);
udp.Send(b1,b1.Length);
}
//**************大于mtu的数据包进行分包,然后发送**********
else
{


//分包的大小
int PacketSize=60000;
//分包的数量
int PacketCount=0;
//分包个数的控制
//totalSize/PacketSize*PacketSize 只有两中情况,等于totalsize 或者是大于

if(totalSize/PacketSize*PacketSize<totalSize)
{ PacketCount=totalSize/PacketSize+1; }
else
{ PacketCount=totalSize/PacketSize; }



//数据包
byte[] data=new byte[PacketSize+1];
//开始循环发送数据包
for(int i=0;i<PacketCount;i++)
{
//分包的起始位置
int start=i*PacketSize;
//最后一个包的发送
if(i==PacketCount-1)
{
//最后一个包的大小
int LastDataPacket=(int)(totalSize-((long)(PacketSize*PacketCount)));
//最后一个数据包的起始位置
int LastDataPacketBegin=totalSize-lastDataPacket;

//给最后一个数据包的前两个自己打标
data[0]=0;
data[1]=i;
Array.Copy(bytes,LastDataPacketBegin,data,2,LastDataPacket)
udp.Send(lastdata,lastdata.Length);
}
//发送分包
else
{
//分包的标记
data[0]=i;
//填充数据包;从bytes源数组提取数据。
Array.Copy(bytes,start,data,1,data.Length);
//发送做过标记的数据包
udp.Send(data,data.Length);
}

}

catch( Exception e)
{
MessageBox.Show(e.ToString());
}
}


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

数据接收:

while(true)
{
RemoteIpEndPoint=null;
try
{

byte[] receiveBytes=receive.Receive(ref RemoteIpEndPoint);

//数据小于30000字节的,处理掉标记后进行输出
if(receiveBytes[0]==1)
{
//长度减1
byte[] b1=new byte[receiveBytes-1] ;
//除去标记
Array.Copy(receiveBytes,1,b1,0,receiveBytes.Length);
//转换数据为string 并显示
string returnData=Encoding.Unicode.GetString(b1,0,b1.Length);
this.richTextBox.Text=returenData;
}
else
{
// ************************
//取得分包的数据

//并组合数据
//************************

}

}

catch(Exception e)
{
MessageBox.Show(e.ToString());
}
}


-----------------------------
由于能力有限,在数据分包上还有很多的错误。请高手指正 !
问题是 : 在接收端,我无发把数据包再组合起来啦 。因为那是个阻塞的方式 !

当然先排除数据包丢失和顺序错误不考虑,怎么样单纯的把数据分包组合起来 ?
下一 步再解决数据包的顺序问题。谢谢啦 !

--------------------
http://blog.china-pub.com/more.asp?name=immelman&id=11692
这个是主程序的代码 。
...全文
409 16 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
12345_ 2005-07-30
  • 打赏
  • 举报
回复
mark
cnming 2005-04-22
  • 打赏
  • 举报
回复
昨晚闲着没事,测试了一下


按照以上的代码,同一次可以传递一篇小文章,其中包括中文、英文、标点符号、换行等等的文本文章
cnming 2005-04-22
  • 打赏
  • 举报
回复
#region methods

private void Listen()
{
int port = 11000;

UdpClient listener = new UdpClient(port);
int m_intSerial = 0;
int m_intBlocks = 0; //数据分割块数
int m_intLength = 0; //数据长度
int m_intMessageLength = 0;
int place = 0;
int m_intGetCount = 0;
IPEndPoint ipep = null;

try
{
while(true)
{
byte[] bytesF = listener.Receive(ref ipep);

place = 0;
m_intSerial = BitConverter.ToInt32(bytesF,place);
place += 4;
m_intBlocks = BitConverter.ToInt32(bytesF,place);
place += 4;
m_intLength = BitConverter.ToInt32(bytesF,place);
place += 4;
m_intMessageLength = BitConverter.ToInt32(bytesF,place);
place += 4;

byte[] data = new byte[m_intMessageLength]; //申明数据的总长

Array.Copy(bytesF, 16, data, m_intBlockLength * m_intSerial, m_intLength); //复制数据

m_intGetCount = m_intGetCount + 1;
Application.DoEvents();

if(m_intBlocks > 1)
{
while(true)
{
byte[] bytes = listener.Receive(ref ipep);

place = 0;
m_intSerial = BitConverter.ToInt32(bytes,place);
place += 4;
m_intBlocks = BitConverter.ToInt32(bytes,place);
place += 4;
m_intLength = BitConverter.ToInt32(bytes,place);
place += 4;
m_intMessageLength = BitConverter.ToInt32(bytes,place);
place += 4;

Array.Copy(bytes, 16, data, m_intBlockLength * m_intSerial, m_intLength); //复制数据

m_intGetCount = m_intGetCount + 1;

Application.DoEvents();

if (m_intGetCount >= m_intBlocks)
{
break;
}
}
}
//string message = Encoding.ASCII.GetString(data, 0, data.Length);
//string message = Encoding.Unicode.GetString(data, 0, data.Length);
string message = System.Text.Encoding.Default.GetString(data, 0, data.Length);
string date = DateTime.Now.ToString();
string history = date + " From: " +
ipep.ToString() + " \r\n" +
message + "\r\n";
this.rtxtHistory.AppendText(history);
this.txtMsg.Select(); // 设置控件焦点
Console.WriteLine("Closed!");

if(message == "Exit")
{
break;
}

}
listener.Close();
}
catch (System.Exception pe)
{
Console.WriteLine(pe.ToString());
}
}
private void Send(string message)
{
IPAddress ip = IPAddress.Parse("255.255.255.255");
int port = 11000;
UdpClient sender = new UdpClient();
IPEndPoint ipep = new IPEndPoint(ip, port);


//byte[] BTmp = Encoding.ASCII.GetBytes(message);
//byte[] BTmp = Encoding.Unicode.GetBytes(message);
byte[] BTmp = System.Text.Encoding.Default.GetBytes(message);
int m_intMessageLength = BTmp.Length;
int m_intSerial = 0;

int m_intBlocks = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(m_intMessageLength)/Convert.ToDouble(m_intBlockLength))); //数据分割块数

while (m_intMessageLength > 0)
{
try
{
int m_intLength = m_intBlockLength; //数据长度

if (m_intMessageLength < m_intLength)
{
m_intLength = m_intMessageLength;
}

byte[] data = new byte[m_intLength+16];

int place = 0;
Buffer.BlockCopy(BitConverter.GetBytes(m_intSerial), 0, data,place,4); //顺序戳
place += 4;
Buffer.BlockCopy(BitConverter.GetBytes(m_intBlocks), 0, data,place,4); //数据总块数
place += 4;
Buffer.BlockCopy(BitConverter.GetBytes(m_intLength), 0, data,place,4); //数据长度
place += 4;
Buffer.BlockCopy(BitConverter.GetBytes(BTmp.Length), 0, data,place,4); //数据总长度
place += 4;
Array.Copy(BTmp, m_intSerial * 1000, data, 16, m_intLength); //复制数据


sender.Send(data, data.Length, ipep);

m_intSerial = m_intSerial + 1;
m_intMessageLength = m_intMessageLength - m_intLength;
}
catch (System.Exception pe)
{
Console.WriteLine(pe.ToString());
}
}
string date = DateTime.Now.ToString();
string history = date + " To: " +
ipep.ToString() + " \r\n" + message + "\r\n";
this.rtxtHistory.AppendText(history);

sender.Close();
}


#endregion

#region events

private void frmBroadcast_Load(object sender, System.EventArgs e)
{
this.mThred = new Thread(new ThreadStart(Listen));
this.mThred.Start();
}
private void frmBroadcast_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.Send("exit");
}
private void frmBroadcast_Closed(object sender, System.EventArgs e)
{
try { this.mThred.Abort(); }
catch(System.Exception pe) { Console.WriteLine(pe.ToString()); }
}
private void txtMsg_TextChanged(object sender, System.EventArgs e)
{
// 控制 buttonSend 的 Enabled 属性
this.buttonSend.Enabled = this.txtMsg.Text != "";
}
private void rtxtHistory_TextChanged(object sender, System.EventArgs e)
{
// 设置 rtxtHistory 控件的文本字体
this.rtxtHistory.Font = this.txtMsg.Font;
}
private void buttonSend_Click(object sender, System.EventArgs e)
{
// 发送网络消息并显示历史信息
this.Send(this.txtMsg.Text);
this.txtMsg.Text = "";
this.txtMsg.Select(); // 设置控件焦点
}


#endregion


}
}
cnming 2005-04-22
  • 打赏
  • 举报
回复
完整的代码:

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace CSDNSample
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class frmBroadcast : System.Windows.Forms.Form
{

#region objects

/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.Container components = null;
private System.Windows.Forms.RichTextBox rtxtHistory;
private System.Windows.Forms.TextBox txtMsg;
private System.Windows.Forms.Button buttonSend;

// 自定义对象
private Thread mThred = null;

private int m_intBlockLength = 1000; //每一个数据包的大小

#endregion

#region constructors

public frmBroadcast()
{
// Windows 窗体设计器支持所必需的
InitializeComponent();
this.txtMsg.Select(); // 设置控件焦点
}


#endregion

#region dispose

/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}


#endregion

#region initialize

/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.rtxtHistory = new System.Windows.Forms.RichTextBox();
this.txtMsg = new System.Windows.Forms.TextBox();
this.buttonSend = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// rtxtHistory
//
this.rtxtHistory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.rtxtHistory.AutoWordSelection = true;
this.rtxtHistory.Location = new System.Drawing.Point(8, 8);
this.rtxtHistory.Name = "rtxtHistory";
this.rtxtHistory.ReadOnly = true;
this.rtxtHistory.Size = new System.Drawing.Size(408, 264);
this.rtxtHistory.TabIndex = 0;
this.rtxtHistory.Text = "";
this.rtxtHistory.TextChanged += new System.EventHandler(this.rtxtHistory_TextChanged);
//
// txtMsg
//
this.txtMsg.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtMsg.Location = new System.Drawing.Point(8, 280);
this.txtMsg.Multiline = true;
this.txtMsg.Name = "txtMsg";
this.txtMsg.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.txtMsg.Size = new System.Drawing.Size(320, 68);
this.txtMsg.TabIndex = 1;
this.txtMsg.Text = "";
this.txtMsg.TextChanged += new System.EventHandler(this.txtMsg_TextChanged);
//
// buttonSend
//
this.buttonSend.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonSend.Enabled = false;
this.buttonSend.Location = new System.Drawing.Point(336, 280);
this.buttonSend.Name = "buttonSend";
this.buttonSend.Size = new System.Drawing.Size(80, 68);
this.buttonSend.TabIndex = 2;
this.buttonSend.Text = "发送(&S)";
this.buttonSend.Click += new System.EventHandler(this.buttonSend_Click);
//
// frmBroadcast
//
this.AcceptButton = this.buttonSend;
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(424, 357);
this.Controls.Add(this.buttonSend);
this.Controls.Add(this.txtMsg);
this.Controls.Add(this.rtxtHistory);
this.Name = "frmBroadcast";
this.Text = "网络消息广播";
this.Closing += new System.ComponentModel.CancelEventHandler(this.frmBroadcast_Closing);
this.Load += new System.EventHandler(this.frmBroadcast_Load);
this.Closed += new System.EventHandler(this.frmBroadcast_Closed);
this.ResumeLayout(false);

}


#endregion

cnming 2005-04-22
  • 打赏
  • 举报
回复
纠正:

Listen中的下面的这个语句有误
Array.Copy(bytesF, 16, data, m_intLength * m_intSerial, m_intLength); //复制数据
针对给你的那个Project,应该改为
Array.Copy(bytesF, 16, data, 1000 * m_intSerial, m_intLength);

此外,byte码的获取最好修改为如下代码
byte[] BTmp = System.Text.Encoding.Default.GetBytes(message);
相对应
string message = System.Text.Encoding.Default.GetString(data, 0, data.Length);
lucbesson 2005-04-22
  • 打赏
  • 举报
回复
谢谢老师 cnming(cnming)

lucbesson 2005-04-20
  • 打赏
  • 举报
回复
问题是:如何把分包的数据组合起来 ?

其他的因素先放一下,一步一步来,初次写网络的东西,还有很多的不足。

这次的问题就是把分包组合起来 。
大雨仔 2005-04-20
  • 打赏
  • 举报
回复
如果有可能的话,我都是建议用WebService来完成的,如果真的要用UPD的的话,要自己合理的定义一下通信协议,这是非常重要的
lucbesson 2005-04-20
  • 打赏
  • 举报
回复
由于能力有限也是初次接触网络编程,还希望朋友多指点一下 !

谢谢
lucbesson 2005-04-20
  • 打赏
  • 举报
回复
再顶

别沉啦
TonyTonyQ 2005-04-20
  • 打赏
  • 举报
回复
问题是:如何把分包的数据组合起来 ?
===================================

可以考虑使用临时文件或内存块来保存各个分包,然后再按顺序依次组合起来。
就是把你的 receiveBytes 变量以二进制方式写到一个临时文件,文件名最好以分包的序号来命名,这样就有很多个临时文件,在完成全部接收或者发现接收到连续的分包时,就可以把这些临时文件合并起来。

不建议你直接转换为 String 来处理,主要是 String 比较占内存,而且大部分二进制数据显示成 String 都是乱码(ASCII的除外)。
zlopen 2005-04-20
  • 打赏
  • 举报
回复
mark
singlepine 2005-04-20
  • 打赏
  • 举报
回复
学习
cnming 2005-04-20
  • 打赏
  • 举报
回复
把你的程序整成一个demo给我好了

cnming@163.com
lih163 2005-04-20
  • 打赏
  • 举报
回复
学习
lucbesson 2005-04-20
  • 打赏
  • 举报
回复
qzj(SoldierQ)说的很好,又学到了一点。

继续收集意见和解决方法 !

谢谢

111,097

社区成员

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

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

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