C# DotNetty (2) EchoClient

上一篇:C# DotNetty (1) EchoServer

客户端同样是参照案例修改,直接贴代码,不废话了

EchoClient:

using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using DotNetty.Codecs;
using DotNetty.Handlers.Logging;
using DotNetty.Handlers.Tls;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using System.Collections.Concurrent;
using DotNetty.Buffers;
using DotNetty.Handlers.Timeout;
using System.Collections.Generic;
using System.Threading;

namespace LocateAnalyzer.DotNetty
{
    class EchoClient
    {
        public static ConcurrentDictionary<string, ClientChannel> clients = new ConcurrentDictionary<string, ClientChannel>();
        private const int Read_TimeOut = 10;
        private const int Write_TimeOut = 30;
        private const int TimeOut = 100;
        public class ClientChannel
        {
            public IChannel channel { get; set; }
            public MultithreadEventLoopGroup group { get; set; }
        }
        public static async Task RunClientAsync(Boolean IsSsl, String LocalPoint, int ReconnectTimes = 0)
        {
            var group = new MultithreadEventLoopGroup();

            X509Certificate2 cert = null;
            string targetHost = null;
            if (IsSsl)
            {
                cert = new X509Certificate2(Path.Combine(AppContext.BaseDirectory, "dotnetty.com.pfx"), "password");
                targetHost = cert.GetNameInfo(X509NameType.DnsName, false);
            }
            try
            {
                var bootstrap = new Bootstrap();
                _ = bootstrap
                    .Group(group)
                    .Channel<TcpSocketChannel>()
                    .Option(ChannelOption.TcpNodelay, true)
                    .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;

                        if (cert != null)
                        {
                            pipeline.AddLast("tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost)));
                        }
                        pipeline.AddLast(new LoggingHandler());
                        pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ByteOrder.LittleEndian, Int32.MaxValue, 4, 4, 0, 0, true));
                        //添加变长协议的Decoder
                        //参数说明:
                        /**
                         * 1.ByteOrder 字节顺序 大端序(低位在后) 或 小端序(低位在前)
                         * 2.maxFrameLength 包体最大长度
                         * 3.lengthFieldOffset 长度字段偏移量 即长度字段的第一个字节前面还有多少个字节
                         * 4.lengthFieldLength 长度字段占字节数
                         * 5.lengthAdjustment 长度补偿 The compensation value to add to the value of the length field.
                         * 6.initialBytesToStrip 解码时跳过的字节数 the number of first bytes to strip out from the decoded frame.
                         * 7.failFast 为true时解码失败抛出异常
                         */
                        pipeline.AddLast("echo", new EchoClientHandler());
                        pipeline.AddLast("framing-enc", new EchoEncoder());//自定义编码器
                        //闲置状态处理器及心跳检测
                        pipeline.AddLast("framing-IdleState", new IdleStateHandler(Read_TimeOut, Write_TimeOut, TimeOut));
                        pipeline.AddLast("framing-HeartBeating", new EchoHeartBeating());
                    }));
                String[] args = LocalPoint.Split(':');
                if (int.TryParse(args[1], out int Port))
                {
                    var bytes = args[0].Split('.');
                    byte[] host = new byte[4];
                    for (int i = 0; i < 4; i++)
                        _ = byte.TryParse(bytes[i], out host[i]);
                    IPAddress Host = new IPAddress(host);
                    IChannel clientChannel = await bootstrap.ConnectAsync(Host, Port).ConfigureAwait(true);
                    ClientChannel client = new ClientChannel()
                    {
                        channel = clientChannel,
                        group = group
                    };
                    clients.TryAdd(LocalPoint, client);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                await StopAsync(LocalPoint).ConfigureAwait(true);
                Console.WriteLine("Reconnecting to " + LocalPoint + ", times:" + (ReconnectTimes + 1));
                Thread.Sleep(5000);
                await RunClientAsync(IsSsl, LocalPoint, ReconnectTimes + 1).ConfigureAwait(true);
            }
        }
        #region Stop
        public static bool Stop(String LocalPoint)
        {

            if (clients.TryRemove(LocalPoint, out ClientChannel client))
            {
                try
                {
                    client.channel.CloseAsync().Wait();
                    client.group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)).Wait();
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    throw;
                }
            }
            else
                return false;
        }
        public static async Task<bool> StopAsync(String LocalPoint)
        {
            if (clients.TryRemove(LocalPoint, out ClientChannel client))
            {
                try
                {
                    await client.channel.CloseAsync().ConfigureAwait(true);
                    await client.group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)).ConfigureAwait(true);
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    throw;
                }
            }
            else
                return false;
        }
        #endregion
        #region Send To Server
        public static void Write(String Address, Object[] msg)
        {
            List<byte> bytes = new List<byte>();
            foreach (var m in msg)
                bytes.AddRange(Util.SocketUtil.StructToBytes(m));
            clients[Address].channel.WriteAndFlushAsync(bytes.ToArray());
        }
        public static async Task WriteAsync(String Address, Object[] msg)
        {
            List<byte> bytes = new List<byte>();
            foreach (var m in msg)
                bytes.AddRange(Util.SocketUtil.StructToBytes(m));
            await clients[Address].channel.WriteAndFlushAsync(bytes.ToArray()).ConfigureAwait(true);
        }
        #endregion 
    }
}

EchoClientHandler

using DotNetty.Buffers;
using DotNetty.Transport.Channels;
using System;
using System.Text;
using LocateAnalyzer.CommandPack;
namespace LocateAnalyzer.DotNetty
{
    internal class EchoClientHandler : ChannelHandlerAdapter
    {
        public override void ChannelRegistered(IChannelHandlerContext context)
        {
            Console.WriteLine(context.Channel.LocalAddress + " Connected");
            base.ChannelRegistered(context);
        }
        public override void ChannelUnregistered(IChannelHandlerContext context)
        {
            Console.WriteLine(context.Channel.LocalAddress + " DisConnected");
            base.ChannelUnregistered(context);
        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            var byteBuffer = message as IByteBuffer;
            if (byteBuffer != null)
            {
                CMDLib.Header hdr = new CMDLib.Header()
                {
                    type = byteBuffer.ReadIntLE(),
                    length = byteBuffer.ReadIntLE()
                };
                CMDLib.Header hdr2 = new CMDLib.Header()
                {
                    type = byteBuffer.ReadIntLE(),
                    length = byteBuffer.ReadIntLE()
                };
                byteBuffer.DiscardReadBytes();
                Console.WriteLine("Client recv:" + hdr.type + "," + hdr.length + "," + hdr2.type + "," + hdr2.length);
                //EchoClient.WriteAsync(context.Channel.RemoteAddress.ToString(), new object[] { hdr, hdr2 }).Wait();
            }
        }
        public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush();

        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
        {
            Console.WriteLine("Exception: " + exception);
            context.CloseAsync();
        }
    }
}

EchoHeartBeating

using DotNetty.Transport.Channels;
using DotNetty.Handlers.Timeout;
using System;

namespace LocateAnalyzer.DotNetty
{
    internal class EchoHeartBeating : SimpleChannelInboundHandler<object>
    {
        public override void UserEventTriggered(IChannelHandlerContext context, object evt)
        {
            if (evt.GetType() == typeof(IdleStateEvent))
            {
                var idleEvent = evt as IdleStateEvent;
                if (idleEvent.State == IdleState.ReaderIdle)
                {
                    //Console.WriteLine("ReaderIdle:" + DateTime.Now.ToLongTimeString());
                    //context.Channel.CloseAsync();
                    base.UserEventTriggered(context, evt);
                }
                else if (idleEvent.State == IdleState.WriterIdle)
                {
                    //Console.WriteLine("WriterIdle:" + DateTime.Now.ToLongTimeString());
                    //context.Channel.CloseAsync();
                    base.UserEventTriggered(context, evt);
                }
                else
                {
                    Console.WriteLine("AllIdle:" + DateTime.Now.ToLongTimeString());
                    context.Channel.CloseAsync();
                    //base.UserEventTriggered(context, evt);
                }
            }
        }

        protected override void ChannelRead0(IChannelHandlerContext ctx, object msg)
        {
            Console.WriteLine("ChannelRead0:" + DateTime.Now.ToLongTimeString());
            throw new NotImplementedException();
        }
    }
}

EchoEncoder

using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Channels;

namespace LocateAnalyzer.DotNetty
{
    internal class EchoEncoder : MessageToByteEncoder<byte[]>
    {
        protected override void Encode(IChannelHandlerContext context, byte[] message, IByteBuffer output)
        {
            output.WriteBytes(message);
        }
    }
}

启动客户端时:

            _ = ThreadPool.QueueUserWorkItem((obj) =>
            {
                DotNetty.EchoClient.RunClientAsync(false, HostStr).Wait();
            });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值