using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Tool
{
/// <summary>
/// UDP数据包分割器
/// </summary>
public static class UdpPacketSplitter
{
/// <summary>
/// 分割UDP数据包
/// </summary>
/// <param name="sequence">UDP数据包所持有的序号</param>
/// <param name="datagram">被分割的UDP数据包</param>
/// <param name="chunkLength">分割块的长度</param>
/// <returns>
/// 分割后的UDP数据包列表
/// </returns>
public static ICollection<UdpPacket> Split(long sequence, byte[] datagram, int chunkLength)
{
if (datagram == null)
throw new ArgumentNullException("datagram"); List<UdpPacket> packets = new List<UdpPacket>(); int chunks = datagram.Length / chunkLength;
int remainder = datagram.Length % chunkLength;
int total = chunks;
if (remainder > 0) total++; for (int i = 1; i <= chunks; i++)
{
byte[] chunk = new byte[chunkLength];
Buffer.BlockCopy(datagram, (i - 1) * chunkLength, chunk, 0, chunkLength);
packets.Add(new UdpPacket(sequence, total, i, chunk, chunkLength, remainder));
}
if (remainder > 0)
{
int length = datagram.Length - (chunkLength * chunks);
byte[] chunk = new byte[length];
Buffer.BlockCopy(datagram, chunkLength * chunks, chunk, 0, length);
packets.Add(new UdpPacket(sequence, total, total, chunk, chunkLength, remainder));
} return packets;
}
}
}

这是分包的算法

这是另外一个类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace Tool
{
[Serializable]
public class UdpPacket
{
public long sequence{get;set;}
public int total { get; set; }
public int i { get; set; }
public byte[] chunk { get; set; }
public int chunkLength { get; set; }
public int remainder { get; set; }
public static int HeaderSize = 30000;
public UdpPacket(long sequence, int total, int i, byte[] chunk, int chunkLength, int remainder)
{
this.sequence = sequence;
this.total = total;
this.i = i;
this.chunk = chunk;
this.chunkLength = chunkLength;
this.remainder = remainder;
}
//把这个对象生成byte[]
public byte[] ToArray()
{
return Model.SerializationUnit.SerializeObject(this);
}
}
}

然后对分包进行发送就行了的

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Collections;
using System.Net;
using Model;
using System.Data;
using Tool;
namespace C_UDPServer
{
public class Server
{
public UdpClient server;
public ArrayList mblist;
IPEndPoint test = null;//构造远程连接的参数
//保存用户的
public Dictionary<string, IPEndPoint> dic = new Dictionary<string, IPEndPoint>();
public bool flag=true;
public Server(int port)
{
IPAddress myIPAddress = null;
//获得当前的ip
try
{
IPAddress[] address = Dns.GetHostAddresses(Dns.GetHostName()); foreach(IPAddress i in address)
{
if (i.AddressFamily.ToString().Equals("InterNetwork"))
{
myIPAddress = i;
break;
}
} }
catch (Exception e)
{ }
//System.Console.Write(myIPAddress);
string hostIP = myIPAddress.ToString(); IPAddress ipS = IPAddress.Parse(hostIP);//初始化本机
IPEndPoint EndPoint = new IPEndPoint(ipS, port);
server = new UdpClient(EndPoint);//创建本地连接
//设置缓冲大小
server.Client.ReceiveBufferSize = 1024 * 1024;
ShowServerinfo(hostIP + "启动成功!"); }
//服务器接收数据的方法,会根据接收到的数据做出判断
public void ReceiveData()
{
ShowServerinfo("等待用户");
//未接收完的包
Dictionary<long, RecDataList> RecListDic = new Dictionary<long, RecDataList>();
while (flag)
{
try
{
//异步接收的....现在还不会
//AsyncCallback callBack = new AsyncCallback(ReceiveComplete);
//server.BeginReceive(callBack, server); byte[] data = server.Receive(ref test);//接收数据,当Client端连接主机的时候,test就变成Cilent端的IP了
Msg msg = null;
UdpPacket udpp = null;
try
{
msg = (Msg)Model.SerializationUnit.DeserializeObject(data);
}
catch (Exception e1)
{
try
{
udpp = (UdpPacket)Model.SerializationUnit.DeserializeObject(data);
}
catch(Exception e2)
{
ShowServerinfo("解析序列话数据错误");
}
//break;
};
if (udpp != null)
{
ShowServerinfo("收到分包数据:" + udpp.i);
if (!RecListDic.ContainsKey(udpp.sequence))
{
RecListDic.Add(udpp.sequence, new RecDataList(udpp));
RecDataList rdl = RecListDic[udpp.sequence];
rdl.addPacket(udpp);
}
else{
RecDataList rdl=RecListDic[udpp.sequence];
rdl.addPacket(udpp); }
foreach (KeyValuePair<long, RecDataList> ss in RecListDic)//循环看看是否有哪一个满了
{
Msg m = ss.Value.show();
if (m != null)
{
ShowServerinfo(m.msg);
RecListDic.Remove(ss.Value.sequence);
break;
} } }
if (msg != null)
{
if (msg.command.Equals("ADD"))
{
string name = msg.name;//获得对象的名字
AddMember(name, test);
}
else if (msg.command.Equals("DEL"))
{
DelMember(test);
}
else if (msg.destinationIP != "")
{
//获得的ip包含了端口号的
string[] s = msg.destinationIP.Split(':');
string ip = s[0];
int port = int.Parse(s[1]);
IPAddress ipS = IPAddress.Parse(ip);
IPEndPoint destinationIP = new IPEndPoint(ipS, port); //单独把某个用户发送消息
SendToSB(test, destinationIP, msg.msg);
//ShowServerinfo("ip:"+msg.destinationIP);
}
else
{
//判断是否这个人是在人员列表中存在
if (dic.ContainsValue(test))
{
SendToMember(test, msg.msg);//转发数据 } }
}
}
catch (Exception e)
{
ShowServerinfo("出异常了");
}
}
}
//异步接收
private void ReceiveComplete(IAsyncResult param)
{
//UdpClient client=(UdpClient)param.AsyncState;//对应的就是BeginSend的最后一个参数state
//IPEndPoint ipep = new IPEndPoint(IPAdress.Any,m_Port);
//byte[] datas=client.EndReceive(param,ref ipep);//接受到的数据
//catch(Exception ex) {}
}
public void AddMember(string nickNmae, IPEndPoint rep)//加入组
{
if (dic.ContainsValue(rep))//如果已经有这用户就返回
{
return;
}
//存有用户信息的字典添加一个用户
dic.Add(nickNmae, rep); MsgService msg = new MsgService("success", "已连接", nickNmae, "");
sendEntitydata(msg,rep); //Console.WriteLine(nickNmae + "[" + rep.ToString() + "]" + "加入了组");
ShowServerinfo(nickNmae + "[" + rep.ToString() + "]" + "加入了组");
SendUserList();
//当用户更新后发送用户列表给所有用户
}
public void DelMember(IPEndPoint rep)//移除组
{
foreach (KeyValuePair<string, IPEndPoint> user in dic)
{
if (user.Value.Equals(rep))
{
MsgService msg = new MsgService("exit", "退出了", "", "");
sendEntitydata(msg, rep); //Console.WriteLine(user.Key + "[" + rep.ToString() + "]" + "退出了组"); ShowServerinfo(user.Key + "[" + rep.ToString() + "]" + "退出了组");
dic.Remove(user.Key);
SendUserList();
break;//否则会报错,因为dic已经被修改
}
}
} public void sendEntitydata(MsgService msg,IPEndPoint rep)
{
byte[] bytes = Model.SerializationUnit.SerializeObject(msg);
//string data = Model.UDPComm.DecodingASCII(bytes);
//byte[] bytedata = UDPComm.EncodingASCII(data);//发送数据
//server.Send(bytedata, bytedata.Length, rep);
server.Send(bytes, bytes.Length, rep);
} //发送用户表
public void SendUserList()
{ string userlist = "UserList";
foreach (KeyValuePair<string, IPEndPoint> ss in dic)//取得所有用户
{
//userlist += "|" + ss.Key;
userlist += "|" + ss.Key + "," + ss.Value.ToString();
} //序列化数据
MsgService msg = new MsgService("userList", "", "", "");
msg.userlist = userlist;//添加用户表
foreach (KeyValuePair<string, IPEndPoint> ss in dic)//把用户表发给每个用户
{
sendEntitydata(msg, ss.Value);
} }
//单独发给某人
public void SendToSB(IPEndPoint user, IPEndPoint destinationIP, string message)
{
string name = "";
string destinationname = "";//收信息的人的名字
foreach (KeyValuePair<string, IPEndPoint> ss in dic)//用来找出这个user的名字
{
if (ss.Value.Equals(user))//不能用"=="因为是两个不同的对象
{
name = ss.Key;//得到发信息的人的名字
}
if (ss.Value.Equals(destinationIP))
{
destinationname = ss.Key;//得到收信人的名字
}
}
if (name != "" && destinationname != "")
{
//在服务端显示信息
ShowServerinfo(name + "[" + user.ToString() + "]:对" + destinationname + "[" + destinationIP.ToString() + "]说:" + message); //序列化数据
MsgService msg = new MsgService("talkone", message, name, destinationname);
sendEntitydata(msg,destinationIP);
sendEntitydata(msg, user);
}
}
public void SendToMember(IPEndPoint user, string message)//组类转发数据(第一个参数是谁发的,第二个是发的内容)
{
string name = "";
foreach (KeyValuePair<string, IPEndPoint> ss in dic)//用来找出这个user的名字
{
if (ss.Value.Equals(user))//不能用"=="因为是两个不同的对象
{
name = ss.Key;//给要发送给各个客户端的信息加上发送人姓名;
//在服务端显示的信息
//Console.WriteLine(name + "[" + user.ToString() + "]:" + message);
ShowServerinfo(name + "[" + user.ToString() + "]:" + message);
break;
}
}
foreach (KeyValuePair<string, IPEndPoint> d in dic)//循环给每个人都发送信息
{
//序列化数据
MsgService msg = new MsgService("talkall", message, name, "");
try
{
sendEntitydata(msg,d.Value);
}
catch (Exception e)
{
ShowServerinfo("给" + name+"发送信息失败!");
DelMember(d.Value);
}
}
}
//返回信息
public void ShowServerinfo(string servermsg)
{
System.Console.WriteLine(servermsg);
} }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tool;
using Model; namespace C_UDPServer
{
//服务端收到数据的数据结构
public class RecDataList
{
public long sequence { get; set; }//序列号
//对应的存储包的List
List<UdpPacket> RecudpPackets = new List<UdpPacket>();
public int total { get; set; }
public int chunkLength { get; set; }
public int remainder { get; set; }
public byte[] DataBuffer = null;
public RecDataList(UdpPacket udp)
{ this.sequence = udp.sequence;
this.total = udp.total;
this.chunkLength = udp.chunkLength;
this.remainder = udp.remainder;
if (DataBuffer == null)
{
DataBuffer = new byte[chunkLength * (total - 1) + remainder];
}
}
public RecDataList(long sequence, int total, int chunkLength, int remainder)
{ this.sequence = sequence;
this.total = total;
this.chunkLength = chunkLength;
this.remainder = remainder;
if (DataBuffer == null)
{
DataBuffer = new byte[this.chunkLength * (this.total - 1) + this.remainder];
}
}
public void addPacket(UdpPacket p)
{
RecudpPackets.Add(p);
}
public Msg show()
{
if (RecudpPackets.Count == total)//表示已经收集满了
{
//重组数据
foreach (UdpPacket udpPacket in RecudpPackets)
{
//偏移量
int offset = (udpPacket.i - 1) * udpPacket.chunkLength;
Buffer.BlockCopy(udpPacket.chunk, 0, DataBuffer, offset, udpPacket.chunk.Length);
}
Msg rmsg = (Msg)Model.SerializationUnit.DeserializeObject(DataBuffer);
DataBuffer = null;
RecudpPackets.Clear();
return rmsg;
}
else
{
return null;
}
}
}
}

客户端代码 分包发送UDP数据


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using Model;
using System.Net.Sockets;
using C_UDPClient;
using Tool;
using System.Threading; namespace UDPClient
{
    public class Client
    {
        public UdpClient client;
        public bool flag = true;
        public String nickname;
        IPEndPoint remotIpEnd = null;//用来在接收数据的时候对远程主机的信息存放
        public int port;
        public string hostIP;
        public Client(string hostIP, int port, string nick)
        {
            IPAddress ipA = IPAddress.Parse(hostIP);//构造远程连接的参数
            IPEndPoint ipEnd = new IPEndPoint(ipA, port);
            client = new UdpClient();// client = new UdpClient(ipEnd)这样的话就没有创建远程连接
            client.Connect(ipEnd);//使用指定的远程主机信息建立默认远程主机连接
            this.nickname = nick;
            this.port = port;
            this.hostIP = hostIP;
        }
        public void SendData(string message)
        {
            try
            {
                byte[] data = UDPComm.EncodingASCII(message);//发送数据
                client.Send(data, data.Length);
            }
            catch (Exception e)
            {
                AddTalkMessage("发送数据异常1!");
                //client.Close();
            }
        }
        //发送大数据的方法
        public void SendManyPacket(Msg message)
        {
            byte[] datagram = null;
            try
            {
                datagram = Model.SerializationUnit.SerializeObject(message);
            }
            catch (Exception e)
            {
                AddTalkMessage("数据转型异常");
            }
           
            Random Rd = new Random();
            long SequenceNumber = Rd.Next(88888, 999999);
            ICollection<UdpPacket> udpPackets = UdpPacketSplitter.Split(SequenceNumber, datagram, 10240);//65507 - UdpPacket.HeaderSize
            foreach (UdpPacket udpPacket in udpPackets)
            {
                byte[] udpPacketDatagram = Model.SerializationUnit.SerializeObject(udpPacket);
                //使用同步发送
                //Thread.Sleep(1000); //如果加了这条就不丢包
                //client.Send(udpPacketDatagram, udpPacketDatagram.Length);
                // 异步发送
                //Thread.Sleep(1000); //如果加了这条就不丢包
                this.client.BeginSend(
                udpPacketDatagram,
                udpPacketDatagram.Length, SendCompleted, new AsyncCallbackArg(udpPacket.i.ToString(), client));
            }
        }
        //发送完成后的回调方法
        public void SendCompleted(IAsyncResult param)
        {
            /*
            //AsyncCallbackArg arg = (AsyncCallbackArg)param.AsyncState ;//param.AsyncState 对应的就是BeginSend的最后一个参数state     
            UdpClient client = (UdpClient)param.AsyncState;
            try
              {
                  client.EndSend(param);//这句话必须得写,BeginSend()和EndSend()是成对出现的
                  AddTalkMessage("数据包发送完毕!");
              }
              catch (Exception e) { }
             */
         } public void SendData(Msg message)
        {
            try
            {
                byte[] bytes = Model.SerializationUnit.SerializeObject(message);
                client.Send(bytes, bytes.Length);
            }
            catch (Exception e)
            {
                AddTalkMessage("发送数据异常2!");
            }
        }
        public void ReceiveData()
        {
            while (flag)
            {
                try
                {
                    byte[] data = client.Receive(ref remotIpEnd);//接收数据,当Client端连接主机的时候,test就变成Cilent端的IP了
                    MsgService msg = null;
                    try
                    {
                        msg = (MsgService)Model.SerializationUnit.DeserializeObject(data);
                    }
                    catch (Exception e)
                    {
                        AddTalkMessage("解析序列话数据错误..");
                    };
                    if (msg.command.Equals("userList"))
                    {
                        AddUserList(msg.userlist);
                        //AddTalkMessage(ReturnData);
                        continue;
                    }
                    if (msg.name.Equals(nickname))
                    {
                        AddTalkMessage(msg);
                    }
                    else
                    {
                        AddTalkMessage(msg); }
                }
                catch (Exception e)
                {
                    AddTalkMessage("未连接..");
                    break;
                }
            }
        }
        public void AddUserList(string s)
        {
            System.Console.WriteLine("用户表为:" + s);
        }
        public void AddTalkMessage(string s)
        {
            System.Console.WriteLine(s);
        }
        public void AddTalkMessage(MsgService s)
        {
            System.Console.WriteLine(s.ToString());
        } //异步发送数据的数据结构
        private struct AsyncCallbackArg
        {
            private UdpClient udpClient;
            private string ipAddress;
            public AsyncCallbackArg(string ip, UdpClient client)
            {
                udpClient = client;
                ipAddress = ip;
            }
        }
    }
}

C#中upd分包与发送,已经实现全部代码的更多相关文章

  1. 如何在优雅地Spring 中实现消息的发送和消费

    本文将对rocktmq-spring-boot的设计实现做一个简单的介绍,读者可以通过本文了解将RocketMQ Client端集成为spring-boot-starter框架的开发细节,然后通过一个 ...

  2. [UWP]UWP中获取联系人/邮件发送/SMS消息发送操作

    这篇博客将介绍如何在UWP程序中获取联系人/邮件发送/SMS发送的基础操作. 1. 获取联系人 UWP中联系人获取需要引入Windows.ApplicationModel.Contacts名称空间. ...

  3. 如何给对话框中的控件发送消息呢?Windows消息分类

    以博文CTabCtrl中介绍的那样,给Tab添加子对话框来显示Tab内容.那么如果这个子对话框中含有个CTreeCtrl控件,有个Button控件,我想要模拟给这两个控件发送消息,该怎么办呢?直接把给 ...

  4. NET中解决KafKa多线程发送多主题的问题

    一般在KafKa消费程序中消费可以设置多个主题,那在同一程序中需要向KafKa发送不同主题的消息,如异常需要发到异常主题,正常的发送到正常的主题,这时候就需要实例化多个主题,然后逐个发送. 在NET中 ...

  5. EBS中使用JAVA方式发送HTML格式邮件

    转自huan.gu专栏:http://blog.csdn.net/gh320/article/details/17174769 EBS中使用JAVA方式发送HTML格式邮件 一.开发工具:JDevel ...

  6. spring MVC 管理HttpClient---实现在java中直接向Controller发送请求

    在spring MVC中,大多数时候是由客户端的页面通过ajax等方式向controller发送请求,但有时候需要在java代码中直接向controller发送请求,这时可以使用HttpCilent实 ...

  7. ReactiveCocoa 中 RACSignal 是怎样发送信号

    前言 ReactiveCocoa是一个(第一个?)将函数响应式编程范例带入Objective-C的开源库.ReactiveCocoa是由Josh Abernathy和Justin Spahr-Summ ...

  8. 如何在MFC DLL中向C#类发送消息

    如何在MFC DLL中向C#类发送消息 一. 引言 由于Windows Message才是Windows平台的通用数据流通格式,故在跨语言传输数据时,Message是一个不错的选择,本文档将描述如何在 ...

  9. java中使HttpDelete可以发送body信息

    java中使HttpDelete可以发送body信息RESTful api中用到了DELETE方法,android开发的同事遇到了问题,使用HttpDelete执行DELETE操作的时候,不能携带bo ...

随机推荐

  1. uiautomator定位元素

  2. Django——请求生命周期

    视图层之视图函数(views) 一个视图函数,简称视图,他可以接受Web请求,并且必须返回一个Web响应,响应内容可以是一个HTML内容,一张图片,一个404错误,一个文档等等,都可以称为web为你响 ...

  3. Xcode 错误问题以及解决方法(后期遇到还会添加)

    1,/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhon ...

  4. String与反序

    将String类型的字符串里的内容进行反序排列得到一个新的String类型字符串,下面提供两种方法实现: 法1.先将原String类型字符串转换为字符数组,通过字符数组来操作各个位上的单个字符,通过对 ...

  5. Nullable类型的问题处理

    public class Calc { public long? Number { get; set; } public long Number1 { get; set; } public long ...

  6. hive--udf函数(开发-4种加载方式)

    UDF函数开发 标准函数(UDF):以一行数据中的一列或者多列数据作为参数然后返回解雇欧式一个值的函数,同样也可以返回一个复杂的对象,例如array,map,struct. 聚合函数(UDAF):接受 ...

  7. mapreduce 运行-指定各种运行参数

    mapreduce指定参数 mapreduce在运行的时候可以指定各种参数,这样可以根据实际的应用场景做一下相关的调整 1.指定运行时cpu的个数 hadoop jar hadoop-core-0.1 ...

  8. Nginx 自定义404、500错误页面跳转

    自定义Nginx错误界面跳转 1.开启Nginx.conf配置文件下的自定义接口参数. http { fastcgi_intercept_errors on; } 2.在Server区域添加自定义的错 ...

  9. [pixhawk笔记]1-编译过程

    好久没有编译过PIXHAWK了,由于项目需要,又买了一个pixhawk2,由于每次编译都会出现新的问题,这次写帖子将过程记录下来. 环境:WIN10+Ubuntu16.04 64位(VMware Wo ...

  10. jQuery UI 自定义样式的日历控件

    在线演示 本地下载