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

原创 2013年09月23日 12:07:51
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;             }         }     } }


 

 

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

c#中关于udp实现可靠地传输(数据包的分组发送)

在做c#中面向无连接的传输时用到了UDP,虽然没有TCP稳定可靠。但是效率是要高些,优势也有,缺点也有 就是有的时候要丢包,有的时候不得不用UDP,但是如何才能比较稳定的实现可靠传输呢,这是一个问题。...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

C#高性能大容量SOCKET并发(五):粘包、分包、解包

使用TCP长连接就会引入粘包的问题,粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。粘包可能由发送方造成,也可能由接收方造成。TCP为提高传输...

WebSocket C# 服务端发送大数据,分包发送大数据 方法

WebSocket 服务端 原生Socket 打包发送超过65535 的大数据方法封装

UDP分包问题

1.在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好?         当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对      ...

C# WinForm实现UDP发送和接收数据

1引入 using System.Net; using System.Net.Sockets; using System.IO; 2 具体实施 建立两个winform项目,1)UDP发送 ...

C# UDP接收和发送

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst...

C#使用UdpClient发送和接收UDP数据示例

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#中upd分包与发送,已经实现全部代码
举报原因:
原因补充:

(最多只允许输入30个字)