C#中upd分包与发送,已经实现全部代码

来源:互联网 发布:淘宝网怎么支付 编辑:程序博客网 时间:2024/05/21 21:43
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;            }        }    }}


 

 

原创粉丝点击