自己仿照某商业组件开发的通讯模块,简单的调用便可实现传文件,即时通讯等内容.
如图,只需要绑定ip便可以通讯
组件下载地址:点击打开链接
调用的方法:
class Program
{
public static DataDispatcher dd;
static void Main(string[] args)
{
dd = new DataDispatcher("192.168.167.105:8003");// 这里填写自己的ip
dd.OnDataArrived += dd_OnDataArrived;
}
static void dd_OnDataArrived(byte[] in_listVariablePool)
{
Console.WriteLine("收到数据!");
VariablePool vp = new VariablePool();
vp.Init(in_listVariablePool);
string ip = (string)vp.Get("IP",0);// 获取发送方的IP
// 以上是接受数据
// 下方是发送数据
vp.Init();
vp.Put("IP", ip);
vp.Put("string", DateTime.Now.ToString());
dd.Send(vp.GetVariablePool(),ip);
}
}
完整源代码:
0.目录:
1.主要通讯层DataDispatcher:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using SocketByUDPClassLibrary;
namespace UDPClassLibrary
{
// 定义一个接受到数据时响应的委托
public delegate void OnDataArrivedDelegate(byte[] in_listVariablePool);
public class DataDispatcher
{
// 定义完成事件
public event OnDataArrivedDelegate OnDataArrived;
// 接收池
private Dictionary<int, DataPools> m_listInDataPools;
// 发送池
private Dictionary<int, DataPools> m_listOutDataPools;
// 本机IP地址
private IPEndPoint m_ipSelfIP;
// 接收时的服务变量
private Socket m_SocketService;
private Thread m_threadStartService;
// 线程锁
private Mutex m_mutexPick;
// 并发缓解
private int m_iPush = 1;
// 等待时间(毫秒)
private int m_iWait = 500;
/// <summary>
/// 构造方法
/// </summary>
public DataDispatcher(string in_strIPInfo)
{
// 获得IP
m_ipSelfIP = StrToEndPoint(in_strIPInfo);
// 数据池初始化
m_listInDataPools = new Dictionary<int, DataPools>();
m_listOutDataPools = new Dictionary<int, DataPools>();
// 启动服务
m_threadStartService = new Thread(StartService);
m_threadStartService.Start();
m_mutexPick = new Mutex();
Thread threadTimer=new Thread(MyTime);
threadTimer.Start();
}
/// <summary>
/// 启动服务
/// </summary>
public void StartService()
{
// 使用Socket服务
m_SocketService = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// 绑定网络地址
m_SocketService.Bind(m_ipSelfIP);
// 客户机IP
IPEndPoint senderPoint = new IPEndPoint(IPAddress.Any, 0);
EndPoint senderEndPoint = (EndPoint)(senderPoint);
// 数据大小
int iDataSize;
// 字节数据
byte[] bData = new byte[2048];
List<byte[]> listIncomeDatas = new List<byte[]>();
Thread threadAllotPack;
object objCustomParm;
// 循环监听是否取到包
while (true)
{
bData = new byte[2048];
//接收信息
iDataSize = m_SocketService.ReceiveFrom(bData, ref senderEndPoint);
// 如果是数据包 接收,如果是重发请求包 重发
if (iDataSize == 2048)
{
// 自定义参数
objCustomParm = new CustomParm(bData, senderEndPoint);
// 添加线程
threadAllotPack = new Thread(AllotPack);
// 分配收到的包
threadAllotPack.Start(objCustomParm);
}
else
{
// 根据信息重发
SendByInfo((ResendInfo)SetByteToValue(bData));
Console.WriteLine("收到请求包");
}
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="in_listToSendData"></param>
/// <param name="in_strDesIP"></param>
public void Send(byte[] in_listToSendData, string in_strDesIP)
{
List<byte> listByte = new List<byte>();
listByte.AddRange(in_listToSendData);
// 设置目标IP,设置TCP端口号
IPEndPoint ipEndPoint = StrToEndPoint(in_strDesIP);
// 调用包组件
ByePacketUtil stPacketUtil = new ByePacketUtil();
// 声明包组变量
List<byte[]> listToSendDatas = stPacketUtil.SplitPacket(listByte);
// 添加到发送池
m_listOutDataPools.Add(stPacketUtil.GetJointHeadID(listToSendDatas[0]), new DataPools(0, 0, null, 30000, listToSendDatas));
foreach (var blistPackage in listToSendDatas)
{
//循环发送每个包
byte[] bSends = new byte[2048];
bSends = blistPackage.ToArray();
// 发送
m_SocketService.SendTo(bSends, bSends.Length, SocketFlags.None, ipEndPoint);
// 缓解并发压力
Thread.Sleep(m_iPush);
}
}
private void SendByInfo(ResendInfo in_resendInfo)
{
int iKey = in_resendInfo.Key;
int iIndex = in_resendInfo.Index;
// 调用包组件
ByePacketUtil packetUtil = new ByePacketUtil();
if (m_listOutDataPools.ContainsKey(iKey))
{
foreach (var bItem in m_listOutDataPools[iKey].PacketParking)
{
// 得到包的Index
int iPacketIndex = packetUtil.GetJointHeadIndex(bItem);
if (iPacketIndex==iIndex)
{
// 发送
m_SocketService.SendTo(bItem, bItem.Length, SocketFlags.None, in_resendInfo.MyEndPoint);
}
}
}
}
/// <summary>
/// 分配收到的包
/// </summary>
/// <param name="in_iData"></param>
private void AllotPack(object in_objCustomParm)
{
byte[] listDataIn = ((CustomParm)in_objCustomParm).ParmBytes;
EndPoint endPointIn = ((CustomParm)in_objCustomParm).ParmEndPoint;
// 默认等待时间(毫秒)
int iLeftDef = 30000;
// 调用包组件
ByePacketUtil packetUtil = new ByePacketUtil();
// 得到包的ID
int iPacketID = packetUtil.GetJointHeadID(listDataIn);
// 得到包的Index
int iPacketIndex = packetUtil.GetJointHeadIndex(listDataIn);
// 得到包的份数
int iPacketCount = packetUtil.GetJointHeadCount(listDataIn);
m_mutexPick.WaitOne();
Console.WriteLine("收到" + iPacketIndex + "/" + iPacketCount);
// 操作接收池
if (m_listInDataPools.ContainsKey(iPacketID))
{
// 存在就存一条
m_listInDataPools[iPacketID].PacketParking.Add(listDataIn);
m_listInDataPools[iPacketID].ExistPack++;
m_listInDataPools[iPacketID].LeftTime = iLeftDef;
}
else
{
// 不存在就新建一条
List<byte[]> listTempDatas = new List<byte[]>();
listTempDatas.Add(listDataIn);
m_listInDataPools.Add(iPacketID, new DataPools(1, iPacketCount, endPointIn, iLeftDef, listTempDatas));
}
// 检查接收此包后是否有完整大包
if (m_listInDataPools[iPacketID].PacketParking.Count() == iPacketCount)
{
// 临时变量池
List<byte> listTempPool;
// 若大包完整执行封包
listTempPool = packetUtil.JointPacket(m_listInDataPools[iPacketID].PacketParking);
if (OnDataArrived != null)
{
// 事件抛出数据
OnDataArrived(listTempPool.ToArray());
}
Console.WriteLine("开始组包");
// 删除相关数据
RemoveByKey(iPacketID);
}
m_mutexPick.ReleaseMutex();
}
/// <summary>
/// 每1秒执行一次丢包检查
/// </summary>
private void MyTime()
{
do
{
Thread.Sleep(m_iWait);
CheckTimesIn();
} while (true);
}
/// <summary>
/// 检查接收池包否完整,若超时则释放资源
/// </summary>
private void CheckTimesIn()
{
foreach (int iItemKey in m_listInDataPools.Keys)
{
DataPools stValue = m_listInDataPools[iItemKey];
stValue.LeftTime -= m_iWait;
if (stValue.LeftTime <= 0)
{
RemoveByKey(iItemKey);
}
else if (stValue.LeftTime <= 27000)
{
if (stValue.ExistPack < stValue.TotalPack)
{
List<ResendInfo> listResendInfos = FindLostPack(iItemKey, m_listInDataPools[iItemKey].EndPoint);
// 请求重发
Resend(listResendInfos);
}
}
}
}
/// <summary>
/// 检查发送池包是否超时,若超时则释放资源
/// </summary>
private void CheckTimesOut()
{
foreach (int iItemKey in m_listOutDataPools.Keys)
{
DataPools stValue = m_listOutDataPools[iItemKey];
stValue.LeftTime -= m_iWait;
if (stValue.LeftTime <= 0)
{
m_listOutDataPools.Remove(iItemKey);
}
}
}
private void Resend(List<ResendInfo> in_listResendInfos)
{
foreach (var stResendInfo in in_listResendInfos)
{
// 缓解并发压力
Thread.Sleep(m_iPush);
byte[] bSends = SetValueToByte(stResendInfo);
// 发送
m_SocketService.SendTo(bSends, bSends.Length, SocketFlags.None, stResendInfo.EndPoint);
Console.WriteLine("重发:" + stResendInfo.Index+"---"+stResendInfo.Key);
}
}
/// <summary>
/// 转换出值字节(序列化)
/// </summary>
/// <param name="in_strFieldName">值名字</param>
/// <returns></returns>
public byte[] SetValueToByte(Object in_objValue)
{
var memoryStream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, in_objValue);
byte[] buffer = memoryStream.ToArray();
memoryStream.Close();
return buffer;
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="in_strFieldName">值名字</param>
/// <returns></returns>
public Object SetByteToValue(byte[] in_listValue)
{
var memoryStream = new MemoryStream(in_listValue);
var formatter = new BinaryFormatter();
Object obj = formatter.Deserialize(memoryStream);
memoryStream.Close();
return obj;
}
/// <summary>
/// 生成重发请求列表
/// </summary>
/// <param name="in_iPackKey"></param>
/// <returns></returns>
private List<ResendInfo> FindLostPack(int in_iPackKey,EndPoint in_EndPoint)
{
// 返回变量
List<ResendInfo> listRes = new List<ResendInfo>();
// 得到总包数
int iCount = ((DataPools)m_listInDataPools[in_iPackKey]).TotalPack;
// 总包数布尔值
bool[] listAllTable = new bool[iCount];
List<byte[]> listPools = m_listInDataPools[in_iPackKey].PacketParking;
// 调用包组件
ByePacketUtil packetUtil = new ByePacketUtil();
foreach (byte[] listItem in listPools)
{
int i = packetUtil.GetJointHeadIndex(listItem);
listAllTable[i] = true;
}
for (int i = 0; i < iCount; i++)
{
if (listAllTable[i] == false)
{
listRes.Add(new ResendInfo(in_iPackKey, in_EndPoint, i, m_ipSelfIP));
}
}
return listRes;
}
/// <summary>
/// 依据ID删除检查池的条目
/// </summary>
/// <param name="in_itemKey"></param>
private void RemoveByKey(int in_itemKey)
{
m_listInDataPools.Remove(in_itemKey);
}
/// <summary>
/// 字符串转ip+端口
/// </summary>
/// <returns></returns>
private IPEndPoint StrToEndPoint(string in_strIPandPort)
{
string strIP = in_strIPandPort.Split(':')[0];
string strPort = in_strIPandPort.Split(':')[1];
IPAddress stIP = IPAddress.Parse(strIP);
IPEndPoint resEndPoint = new IPEndPoint(stIP, int.Parse(strPort));
return resEndPoint;
}
}
}
2变量池(存放接收的原始对象):VariablePool
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace SocketByUDPClassLibrary
{
public class VariablePool
{
private List<byte> m_listTransports;
private int m_iPost;
private static int PostInitValue = 2;
/// <summary>
/// 返回变量池
/// </summary>
/// <returns></returns>
public byte[] GetVariablePool()
{
SetCount();
return this.m_listTransports.ToArray();
}
/// <summary>
/// Put时初始化
/// </summary>
public void Init()
{
m_listTransports = new List<byte>();
m_listTransports.AddRange(BitConverter.GetBytes(new ushort()));
}
/// <summary>
/// Get时初始化
/// </summary>
/// <param name="in_listData">接收到的List</param>
public void Init(byte[] in_listData)
{
m_listTransports = new List<byte>();
m_listTransports.AddRange(in_listData);
}
/// <summary>
/// 取得下一个值
/// </summary>
/// <param name="in_iPost"></param>
/// <returns></returns>
public byte[] GetNextData()
{
byte bLength = m_listTransports[m_iPost];
byte[] listResData = new byte[bLength];
int iNextOne = 1;
Array.Copy(m_listTransports.ToArray(), m_iPost + iNextOne, listResData, 0, bLength);
m_iPost += bLength + iNextOne;
return listResData;
}
/// <summary>
/// 获得最大重复值数量
/// </summary>
/// <returns></returns>
public int GetCount()
{
byte[] bUshot = new byte[2];
bUshot[0] = m_listTransports[0];
bUshot[1] = m_listTransports[1];
return BitConverter.ToInt16(bUshot, 0);
}
/// <summary>
/// 修改最大值
/// </summary>
public void SetCount()
{
Dictionary<string, int> listCountMap = new Dictionary<string, int>();
string strName;
m_iPost = PostInitValue;
do
{
strName = Encoding.Default.GetString(GetNextData());
if (listCountMap.ContainsKey(strName))
{
// 如果包含就增加1
listCountMap[strName]++;
}
else
{
// 不包含就新键一条
listCountMap.Add(strName, 1);
}
// 取值过程,只需要下标变动,不需要接收返回值
GetNextData();
// 当下标越界时结束循环
} while (m_iPost < m_listTransports.Count);
// 找出最大值并修改
ushort usMax = (ushort)listCountMap.Values.Max();
byte[] bUshot = BitConverter.GetBytes(usMax);
m_listTransports[0] = bUshot[0];
m_listTransports[1] = bUshot[1];
}
/// <summary>
/// 从变量池取得对象
/// </summary>
/// <param name="in_strFieldName">字段名</param>
/// <param name="in_iIndex">下标</param>
/// <returns></returns>
public object Get(string in_strFieldName, int in_iIndex)
{
int iCount = -1;
List<byte> listResData = new List<byte>();
string strName;
byte[] listValue;
m_iPost = PostInitValue;
do
{
strName = Encoding.Default.GetString(GetNextData());
if (strName == in_strFieldName)
{
// 匹配字段名
iCount++;
}
listValue = GetNextData();
if (iCount == in_iIndex)
{
// 匹配下标
return SetByteToValue(listValue);
}
// 当下标越界时结束循环
} while (m_iPost < m_listTransports.Count);
return null;
}
/// <summary>
/// 转换出字段名字节
/// </summary>
/// <param name="in_strFieldName">字段名字</param>
/// <returns></returns>
public byte[] SetNameToByte(string in_strFieldName)
{
return System.Text.Encoding.ASCII.GetBytes(in_strFieldName);
}
/// <summary>
/// 为变量池添加对象
/// </summary>
/// <param name="in_strFieldName"></param>
/// <param name="in_objValue"></param>
public void Put(string in_strFieldName, Object in_objValue)
{
// 分别转换出字段长度,字段,值长度,值
byte[] listFieldName = SetNameToByte(in_strFieldName);
byte bFieldNameLength = (byte)listFieldName.Length;
byte[] listValue = SetValueToByte(in_objValue);
byte bValueLength = (byte)listValue.Length;
m_listTransports.Add(bFieldNameLength);
m_listTransports.AddRange(listFieldName);
m_listTransports.Add(bValueLength);
m_listTransports.AddRange(listValue);
}
/// <summary>
/// 转换出值字节(序列化)
/// </summary>
/// <param name="in_strFieldName">值名字</param>
/// <returns></returns>
public byte[] SetValueToByte(Object in_objValue)
{
var memoryStream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(memoryStream, in_objValue);
byte[] buffer = memoryStream.ToArray();
memoryStream.Close();
return buffer;
}
/// <summary>
/// 反序列化
/// </summary>
/// <param name="in_strFieldName">值名字</param>
/// <returns></returns>
public Object SetByteToValue(byte[] in_listValue)
{
var memoryStream = new MemoryStream(in_listValue);
var formatter = new BinaryFormatter();
Object obj = formatter.Deserialize(memoryStream);
memoryStream.Close();
return obj;
}
}
}
3.拆包解包工具类ByePacketUtil
using System;
using System.Collections.Generic;
using System.Linq;
namespace SocketByUDPClassLibrary
{
public class ByePacketUtil
{
private int PacketMaxSize = 2048;
private int UserMaxSize = 2040;
private int HeadSize = 8;
private int HeadIndexSize = 2;
private int HeadCountSize = 2;
private int HeadLengthSize = 2;
private int HeadIDSize = 2;
/// <summary>
/// 拆包
/// </summary>
/// <param name="in_listPools"></param>
/// <returns></returns>
public List<byte[]> SplitPacket(List<byte> in_listPools)
{
List<byte[]> listResBytes = new List<byte[]>();
// 得到总长度
int iPoolLenght = in_listPools.Count();
Int16 HeadIndex = -1;
Int16 HeadCount = GetCount(iPoolLenght);
Int16 HeadLength = 0;
Int16 HeadID = CreateID();
//剩下的长度
int iLeftLenght = in_listPools.Count();
bool bIsOver = false;
do
{
// 序列自增
HeadIndex++;
// 判断剩下的长度是否还要再分一个包
if (iLeftLenght > UserMaxSize)
{
// 多个包就是HeadLength=UserMaxSize=2042
HeadLength = (Int16)(UserMaxSize);
}
else
{
// 否则HeadLength等于剩下的大小
HeadLength = (Int16)iLeftLenght;
// 标记循环结束
bIsOver = true;
}
// 建立一个包
List<byte> listResData = new List<byte>();
// 添加包头
listResData.AddRange(CreateHead(HeadIndex, HeadCount, HeadLength, HeadID));
byte[] listPatyData = new byte[HeadLength];
// 依照HeadLength长度剪切in_listPools
Array.Copy(in_listPools.ToArray(), iPoolLenght - iLeftLenght, listPatyData, 0, (long)HeadLength);
//添加剩下内容
listResData.AddRange(listPatyData);
while (listResData.Count<2048)
{
listResData.AddRange(new byte[2048-listResData.Count]);
}
listResBytes.Add(listResData.ToArray());
// 剩下的长度减掉单前包的长度
iLeftLenght -= HeadLength;
} while (!bIsOver);
return listResBytes;
}
/// <summary>
/// 封包
/// </summary>
/// <param name="in_listBytes"></param>
/// <returns></returns>
public List<byte> JointPacket(List<byte[]> in_listBytes)
{
List<byte> listResDatas = new List<byte>();
Dictionary<short, List<byte>> listPacketMap = new Dictionary<short, List<byte>>();
//
short iCount = GetJointHeadCount(in_listBytes[0]);
foreach (byte[] listData in in_listBytes)
{
// 得到索引
short iHeadIndex = GetJointHeadIndex(listData);
// 得到长度
short iHeadLength = GetJointHeadLength(listData);
byte[] listToAdd = new byte[iHeadLength];
Array.Copy(listData, HeadSize, listToAdd, 0, iHeadLength);
// 添加一段到字典
List<byte> listSignal = new List<byte>();
listSignal.AddRange(listToAdd);
listPacketMap.Add(iHeadIndex, listSignal);
}
// 循环按照顺序添加到列表
for (short i = 0; i < iCount; i++)
{
listResDatas.AddRange(listPacketMap[i].ToArray());
}
return listResDatas;
}
/// <summary>
/// 封包时得到包序号
/// </summary>
/// <param name="listData"></param>
/// <returns></returns>
public short GetJointHeadIndex(byte[] listData)
{
byte[] listIndex = new byte[HeadIndexSize];
Array.Copy(listData, 0, listIndex, 0, HeadIndexSize);
return BitConverter.ToInt16(listIndex, 0);
}
/// <summary>
/// 封包时得到总包数
/// </summary>
/// <param name="listData"></param>
/// <returns></returns>
public short GetJointHeadCount(byte[] listData)
{
byte[] listCount = new byte[HeadCountSize];
Array.Copy(listData, HeadIndexSize, listCount, 0, HeadCountSize);
return BitConverter.ToInt16(listCount, 0);
}
/// <summary>
/// 封包时得到内容长度
/// </summary>
/// <param name="listData"></param>
/// <returns></returns>
private short GetJointHeadLength(byte[] listData)
{
byte[] listLength = new byte[HeadLengthSize];
Array.Copy(listData, HeadIndexSize + HeadCountSize, listLength, 0, HeadLengthSize);
return BitConverter.ToInt16(listLength, 0);
}
/// <summary>
/// 封包时得到包ID
/// </summary>
/// <param name="listData"></param>
/// <returns></returns>
public short GetJointHeadID(byte[] listData)
{
byte[] listID = new byte[HeadIndexSize];
Array.Copy(listData, HeadIndexSize + HeadCountSize + HeadLengthSize, listID, 0, HeadIndexSize);
return BitConverter.ToInt16(listID, 0);
}
/// <summary>
/// 创建一个包头
/// </summary>
/// <param name="in_iHeadIndex">序号</param>
/// <param name="in_iHeadCount">总数</param>
/// <param name="in_iHeadLength">内容长度</param>
/// <returns></returns>
public byte[] CreateHead(Int16 in_iHeadIndex, Int16 in_iHeadCount, Int16 in_iHeadLength, Int16 in_iHeadID)
{
List<byte> bHead = new List<byte>();
byte[] bHeadIndex = new byte[HeadIndexSize];
byte[] bHeadCount = new byte[HeadCountSize];
byte[] bHeadLength = new byte[HeadLengthSize];
byte[] bHeadID = new byte[HeadIDSize];
bHeadIndex = BitConverter.GetBytes(in_iHeadIndex);
bHeadCount = BitConverter.GetBytes(in_iHeadCount);
bHeadLength = BitConverter.GetBytes(in_iHeadLength);
bHeadID = BitConverter.GetBytes(in_iHeadID);
bHead.AddRange(bHeadIndex);
bHead.AddRange(bHeadCount);
bHead.AddRange(bHeadLength);
bHead.AddRange(bHeadID);
return bHead.ToArray();
}
/// <summary>
/// 拆包时统计包的数量
/// </summary>
/// <param name="iPoolLenght"></param>
/// <returns></returns>
private short GetCount(int iPoolLenght)
{
return (short)(iPoolLenght / (PacketMaxSize - HeadSize) + 1);
}
/// <summary>
/// 生成一个2字节的ID
/// </summary>
/// <returns></returns>
private short CreateID()
{
return (short)(new Random().Next(65535));
}
}
}
4.一些自定义变量:CustomParm,DataPools,ResendInfo
class CustomParm
{
public byte[] ParmBytes { get; set; }
public EndPoint ParmEndPoint { get; set; }
public CustomParm(byte[] ParmBytes, EndPoint ParmEndPoint)
{
this.ParmBytes = ParmBytes;
this.ParmEndPoint = ParmEndPoint;
}
}
class DataPools
{
public int ExistPack { get; set; }
public int TotalPack { get; set; }
public EndPoint EndPoint { get; set; }
public int LeftTime { get; set; }
public List<byte[]> PacketParking { get; set; }
public DataPools(int ExistPack, int TotalPack, EndPoint EndPoint, int LeftTime, List<byte[]> PacketParking)
{
this.ExistPack = ExistPack;
this.TotalPack = TotalPack;
this.EndPoint = EndPoint;
this.LeftTime = LeftTime;
this.PacketParking = PacketParking;
}
}
[Serializable]// 注意这里的可序列化标志
class ResendInfo
{
public int Key { get; set; }
public EndPoint EndPoint { get; set; }
public int Index { get; set; }
public EndPoint MyEndPoint { get; set; }
public ResendInfo(int Key, EndPoint EndPoint, int Index, EndPoint MyEndPoint)
{
this.Key = Key;
this.EndPoint = EndPoint;
this.Index = Index;
this.MyEndPoint = MyEndPoint;
}
}