java udp 同一个端口实现收发_C#/Udp-1.收发通信基础库的实现

摘要

基本UDP收发通信基础库的实现

C#/Udp-1.收发通信基础库的实现 | Loong Egg​loongegg.github.io
baaed92c20117b7adec78eeb178c5cc0.png
[蛋兄]-71 .net跨平台UdpReceiver基础库创建_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com
1daf27b2f8b98603de180d85d608df07.png

前言

1.系列主题

本系列文章,旨在实现使用Json进行配置的Udp收发器 An Udp Sender & Receiver using json file to configure

2.目标框架(target framework)

  • .net framework 4.5 to support using in windows with .net framework >= 4.5
  • .net standard 2.0 to support using in linux with .net core >= 2.0

3.项目依赖(Dependency)

  • LoongEgg.LoongLog an OpenSource cross-platform & cross-framework log tool, you can get it from nuget or my github
  • Newtonsoft.Json

4.项目地址(Source code)

  • github

5.发行版获取

  • Search in nuget: LoongEgg.UdpCore

UdpReceivedEventArgs.cs

    /// <summary>
    /// Udp接收事件
    /// </summary>
    public delegate void UdpReceivedEvent(object sender, UdpReceivedEventArgs args);

    /// <summary>
    /// Udp接收事件参数
    /// </summary>
    public class UdpReceivedEventArgs: EventArgs
    {
        /// <summary>
        /// 接收到的缓存信息
        /// </summary>
        public byte[] Buffer { get; set; }

        /// <summary>
        /// 默认构造器
        /// </summary>
        /// <param name="buffer"></param>
        public UdpReceivedEventArgs(byte[] buffer)
        {
            Buffer = buffer;
        }
    }

UdpReceiver.cs

1. Events

    /// <summary>
    /// 接收到新消息事件
    /// </summary>
    public event UdpReceivedEvent MessageRecieved;

2. Fields

        /// <summary>
        /// 默认配置文件
        /// </summary>
        private static readonly string DefaultConfigFile = "config.udpreceiver.json";

        /// <summary>
        /// 使用说明
        /// </summary>
        private static readonly string Usage =
            Environment.NewLine + "    Usage: -p port  [-g groupaddress] [-t tag]" +
            Environment.NewLine + "           -p port number listen to" +
            Environment.NewLine + "           -g group address(224.0.0.0, 239.255.255.255)" +
            Environment.NewLine + "           -t tag" +
            Environment.NewLine + "     Info: config options will be saved as config.udpreceiver.json";

3. Properties

        /// <summary>
        /// 端口号
        /// </summary>
        public int Port { get; set; }

        /// <summary>
        /// 组地址
        /// </summary>
        public string GroupAddress { get; set; }

        /// <summary>
        /// 接收器标识
        /// </summary>
        public string Tag { get; set; }

4. Constructors

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public UdpReceiver() { }

        /// <summary>
        /// 创建一个新的接收器
        /// </summary>
        /// <param name="port">端口号</param>
        /// <param name="groupAddress">组地址</param>
        public UdpReceiver(int port, string groupAddress = null)
        {
            GroupAddress = groupAddress;
            Port = port;
        }

5. Public Methods

 /// <summary>
        /// 默认控制台程序实现
        /// </summary>
        /// <param name="useDefaultConfig">default=true, 使用默认的配置文件</param>
        public static UdpReceiver DefaultConsole(bool useDefaultConfig = true)
        {
            string hostName = Dns.GetHostName();
            IPAddress[] IPs = Dns.GetHostAddresses(hostName);
            Logger.Info($"HostName: {hostName}, Local IP(s):");
            if (IPs.Any())
            {
                IPs.ToList().ForEach(ip =>
                {
                    if (ip.AddressFamily == AddressFamily.InterNetwork)
                        Logger.Info($"    {ip.ToString()}");
                });
            }
            Logger.Info($"Try reading default UDP receiver config:{DefaultConfigFile}");

            UdpReceiver receiver = null;
            if (useDefaultConfig && File.Exists(DefaultConfigFile))
            {
                using (StreamReader reader = File.OpenText(DefaultConfigFile))
                {
                    JsonSerializer serializer = JsonSerializer.Create();
                    receiver = serializer.Deserialize(reader, typeof(UdpReceiver)) as UdpReceiver;
                    if (receiver != null)
                    {
                        Logger.Info(receiver.ToString());
                        Logger.Info("Reading default config OK.");
                    }
                }
            }
            else
            {
                Logger.Warn("Reading default UDP receiver config falied!");
                Logger.Info(Usage);
                bool unconfig = true;
                do
                {
                    Logger.Info("Input udp config options:");
                    string command = Console.ReadLine();
                    string[] args = command.Split(' ');
                    int port;
                    string group;
                    string tag;
                    ParseCommandOptions(args, out port, out group, out tag);
                    if (port != 0)
                    {
                        receiver = new UdpReceiver { Port = port, GroupAddress = group, Tag = tag };
                        Logger.Info("Udp initial as: " + receiver.ToString() + "?");
                        Logger.Info($"Enter Y/y to confirm, and save as [{DefaultConfigFile}]. OR any other keys to reinput.");
                        unconfig = !(Console.ReadLine().ToLower() == "y");
                    }
                    else
                    {
                        Logger.Warn("option missed: -p [port number] ");
                    }
                } while (unconfig);
                string json = JsonConvert.SerializeObject(receiver, Formatting.Indented);
                using (StreamWriter writer = File.CreateText(DefaultConfigFile))
                {
                    writer.Write(json);
                    writer.Flush();
                    writer.Close();
                }
            }
            return receiver;
        }

        /// <summary>
        /// 接收器工作
        /// </summary> 
        /// <returns></returns>
        public async Task ReceiveAsync()
        {
            using (var client = new UdpClient(Port))
            {
                if (GroupAddress != null)
                {
                    Logger.Debug($"Join Multicast Group = {GroupAddress}");
                    client.JoinMulticastGroup(IPAddress.Parse(GroupAddress));
                }

                Logger.Debug("Start Listening...Sending in [stop] to stop listening");
                bool completed;
                do
                {
                    UdpReceiveResult result = await client.ReceiveAsync();
                    byte[] datagram = result.Buffer;
                    MessageRecieved?.Invoke(this, new UdpReceivedEventArgs(datagram));
                    string received = Encoding.UTF8.GetString(datagram);
                    Logger.Info($"Received (from {result.RemoteEndPoint.Address}) < {received}");
                    completed = (received.ToLower() == "stop");
                } while (!completed);

                if (GroupAddress != null)
                {
                    client.DropMulticastGroup(IPAddress.Parse(GroupAddress));
                }

                Logger.Warn("Listening stop command received.");
                Logger.Warn("Udp is stopping...");
            }
        }

        /// <summary>
        /// 显示Tag、Port、GroupAddress等详细信息
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return $"{nameof(Port)}={Port}, {nameof(GroupAddress)}={GroupAddress ?? "null"}, {nameof(Tag)}={(Tag ?? "null")}";
        }

6. Private Methods

        /// <summary>
        /// 将数组转义到确切的UDP配置定义
        /// </summary>
        /// <param name="args">命令参数</param>
        /// <param name="port">端口号</param>
        /// <param name="group">组地址</param>
        /// <param name="tag">识别标签</param>
        private static void ParseCommandOptions(string[] args, out int port, out string group, out string tag)
        {
            UdpHelper.TryParseCommandParam(args, "-p", out port);
            UdpHelper.TryParseCommandParam(args, "-g", out group);
            UdpHelper.TryParseCommandParam(args, "-t", out tag);
        }

UdpSender.cs

1.Fields

        /// <summary>
        /// IP端口
        /// </summary>
        private IPEndPoint EndPoint;
        /// <summary>
        /// Udp端口
        /// </summary>
        private UdpClient UdpClient;

        private const string DefaultConfigFile = "config.udpsender.json";

2.Properties

        /// <summary>
        /// 端口号
        /// </summary>
        public int Port { get; set; } = 5566;

        /// <summary>
        /// 组播
        /// </summary>
        public bool IsBroadCast { get; set; }

        /// <summary>
        /// 组地址
        /// </summary>
        public string GroupAddress { get; set; }

        /// <summary>
        /// 主机名字
        /// </summary>
        public string HostName { get; set; }

        /// <summary>
        /// 小端在前?
        /// </summary>
        public bool LittleEndian { get; set; }

        /// <summary>
        /// IpV6模式?
        /// </summary>
        public bool IsIpV6 { get; set; }

        /// <summary>
        /// 标识
        /// </summary>
        public string Tag { get; set; }

3.Constructors

       /// <summary>
        /// Udp发送器的构造器, 创建后不要忘记调用<see cref="Init()"/>进行初始化
        /// </summary>
        /// <param name="port">端口号</param>
        /// <param name="isBroadcast">组播?</param> 
        /// <param name="groupAddress">组地址</param>
        /// <param name="isIpV6">IpV6模式?</param>
        [Obsolete("直接使用方法CreatFromConfig()更香,使用默认构造器,初始化时指定属性")]
        public UdpSender(
            int port,
            bool isBroadcast = true,
            string groupAddress = null,
            bool isIpV6 = false)
        {
            Port = port;
            IsBroadCast = isBroadcast;
            GroupAddress = groupAddress;
            IsIpV6 = IsIpV6; 
        }

        /// <summary>
        /// 默认构造器, 创建后不要忘记调用<see cref="Init()"/>进行初始化
        /// </summary>
        public UdpSender() { }

3.Public Methods

        /// <summary>
        /// 从指定的配置文件创建一个发送器
        /// </summary>
        /// <param name="path">配置文件路径</param>
        /// <returns></returns>
        public static UdpSender CreatFromConfig(string path = null)
        {
            if (path == null)
            {
                if (File.Exists(DefaultConfigFile))
                {
                    using (StreamReader reader = File.OpenText(DefaultConfigFile))
                    {
                        JsonSerializer serializer = JsonSerializer.Create();
                        if (serializer.Deserialize(reader, typeof(UdpSender)) is UdpSender sender)
                        {
                            Logger.Info($"Reading default [{DefaultConfigFile}] config OK.");
                            return sender;
                        }
                        else
                        {
                            string message = $"UdpSender creat from default config file [{DefaultConfigFile}] failed";
                            Logger.Warn(message);
                            throw new ArgumentException(message);
                        }
                    }
                }
                else
                {
                    Logger.Warn($"Reading default config file [{DefaultConfigFile}] failed.");
                    Logger.Warn("UdpSender creat with default property");
                    return new UdpSender();
                }
            }
            else
            {
                using (StreamReader reader = File.OpenText(path))
                {
                    JsonSerializer serializer = JsonSerializer.Create();
                    if (serializer.Deserialize(reader, typeof(UdpSender)) is UdpSender sender)
                    {
                        Logger.Info("Reading default config OK.");
                        return sender;
                    }
                    else
                    {
                        string message = $"UdpSender creat from specifit config file [{path}] failed";
                        Logger.Warn(message);
                        throw new ArgumentException(message);
                    }
                }
            }
        }

        /// <summary>
        /// 发送信息
        /// </summary>
        /// <param name="message">待发送的信息</param>
        /// <returns></returns>
        public async void SendAsync(string message)
        {
            if (EndPoint == null || UdpClient == null)
                throw new InvalidOperationException("Init() before first sending");
            try
            {
                Logger.Info($"Send > {message}");
                byte[] datagram = Encoding.UTF8.GetBytes(message);
                await UdpClient.SendAsync(datagram, datagram.Length, EndPoint);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
       /// <summary>
        /// 初始化端口
        /// </summary>
        public void Init()
        {
            try
            {
                EndPoint = GetIPEndPoint(Port, IsBroadCast, HostName, GroupAddress, IsIpV6).Result;
                UdpClient = new UdpClient
                {
                    EnableBroadcast = IsBroadCast
                };
                if (GroupAddress != null && GroupAddress.ToLower() != "null")
                {
                    UdpClient.JoinMulticastGroup(IPAddress.Parse(GroupAddress));
                }
                Logger.Info("Udp sender initialized");
                Logger.Info(this.ToString() );
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 将配置属性转为字符串
        /// </summary>
        /// <returns></returns>
        public override string ToString() =>
            Environment.NewLine + $"UdpSender: "
            + Environment.NewLine + $"    {nameof(Port)}={Port}"
            + Environment.NewLine + $"    {nameof(IsBroadCast)}={IsBroadCast}"
            + Environment.NewLine + $"    {nameof(HostName)}={HostName}"
            + Environment.NewLine + $"    {nameof(GroupAddress)}={GroupAddress}"
            + Environment.NewLine + $"    {nameof(IsIpV6)}={IsIpV6}";
        /*--------------------------------- Private Methods -------------------------------*/
        /// <summary>
        /// 获取指定的IP端口
        /// </summary>
        /// <param name="port">端口号</param>
        /// <param name="isBroadcast">组播?</param>
        /// <param name="hostName">主机名称</param>
        /// <param name="groupAddress">组地址</param>
        /// <param name="isIpV6">IpV6模式?</param>
        /// <returns></returns>
        private static async Task<IPEndPoint> GetIPEndPoint(
            int port,
            bool isBroadcast,
            string hostName,
            string groupAddress,
            bool isIpV6)
        {
            IPEndPoint endpoint;
            try
            {
                if (isBroadcast)
                {
                    endpoint = new IPEndPoint(IPAddress.Broadcast, port);
                    Logger.Info($"{nameof(isBroadcast)}={isBroadcast}, {nameof(port)}={port} ");
                }
                else if (hostName != null)
                {
                    IPHostEntry hostEntry = await Dns.GetHostEntryAsync(hostName);
                    IPAddress address;
                    if (isIpV6)
                    {
                        address = hostEntry.AddressList.Where(
                            a => a.AddressFamily == AddressFamily.InterNetworkV6
                        ).FirstOrDefault();
                    }
                    else
                    {
                        address = hostEntry.AddressList.Where(
                            a => a.AddressFamily == AddressFamily.InterNetwork
                        ).FirstOrDefault();
                    }
                    endpoint = new IPEndPoint(address, port);
                    Logger.Info($"{nameof(hostName)}={hostName}, {nameof(address)}={address}, {nameof(isIpV6)}={isIpV6}");
                }
                else if (groupAddress != null)
                {
                    endpoint = new IPEndPoint(IPAddress.Parse(groupAddress), port);
                    Logger.Info($"{nameof(groupAddress)}={groupAddress}, {nameof(port)}={port} ");

                }
                else
                {
                    throw new InvalidOperationException($"{nameof(hostName)}, {nameof(isBroadcast)}, or {nameof(groupAddress)} must be set");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return endpoint;
        }

 

~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值