dotnetty使用过程中遇到的问题记录

举报
王阿毛 发表于 2020/04/22 17:17:38 2020/04/22
【摘要】 以启动服务端为例,dotnetty在管道中会配置简单的解码,如果需要分包发送数据,或者一些复杂的发送数据场景中,可以在管道中配置IChannelHandler类,具体分几类可以在网上查相关资料,以代码为例,LengthFieldPrepender中的4代表发送的数据中前4个字节表示为数据长度,后续的才是实际要用到的数据,在自定义的EchoServerHandler方法的ChannelRead...


  1. 以启动服务端为例,dotnetty在管道中会配置简单的解码,如果需要分包发送数据,或者一些复杂的发送数据场景中,可以在管道中配置IChannelHandler类,具体分几类可以在网上查相关资料,以代码为例,LengthFieldPrepender中的4代表发送的数据中前4个字节表示为数据长度,后续的才是实际要用到的数据,在自定义的EchoServerHandler方法的ChannelRead方法中的message变量,会体现出来获取到的实际字节。如果这里配置的数据出错就会产生粘包,排查发送及接收的配置即可。

   /// <summary>
        /// 启动服务端
        /// </summary>
        /// <returns></returns>
        public static async Task RunServerAsync(int port, int type)
        {
            IEventLoopGroup mainGroup;
            IEventLoopGroup workerGroup;
            mainGroup = new MultithreadEventLoopGroup(1);
            workerGroup = new MultithreadEventLoopGroup();
            var bootstrap = new ServerBootstrap();
            try
            {
                bootstrap.Group(mainGroup, workerGroup);
                bootstrap.Channel<TcpServerSocketChannel>();
                bootstrap.Option(ChannelOption.SoBacklog, 100)
                    .Handler(new LoggingHandler("DotNetty-LSTN"))
                    .ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline;
                        pipeline.AddLast(new LoggingHandler("DotNetty-CONN"));
                        //pipeline.AddLast("DotNetty-enc", new  LengthFieldPrepender(4));
                        //pipeline.AddLast("DotNetty-dec", new  LengthFieldBasedFrameDecoder(int.MaxValue, 0, 4, 0, 4));
                        pipeline.AddLast("echo", new EchoServerHandler(type));
                    }));
                IChannel clientchannel = await  bootstrap.BindAsync(port).ConfigureAwait(true);
                MainWindow.EPrintLog("开始监听端口" + port);
                //// 关闭服务
                //await clientchannel.CloseAsync().ConfigureAwait(true);
            }
            catch (Exception ex)
            {
                MainWindow.EPrintLog(ex.ToString());
                await Task.WhenAll(
                    mainGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100),  TimeSpan.FromMilliseconds(1)),
                     workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100),  TimeSpan.FromMilliseconds(1))).ConfigureAwait(false);
            }
            //finally
            //{
            //    await Task.WhenAll(
            //         mainGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100),  TimeSpan.FromMilliseconds(1)),
            //         workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100),  TimeSpan.FromMilliseconds(1))).ConfigureAwait(false);
            //}
        }
  1. dotnetty解码器其中有一种是自定义长度,关键字是LengthFieldPrepender,但是虽然说叫自定义长度,但是只支持数据报文长度占1,2,3,4,8个字节这几种长度,项目中偏偏是定义了前6位字节为报文长度,搞得人很被动,只能自己解码了,其中遇到了这样一个问题:

           A请求数据长度为1400字节,分了两次发送,第一次发送了1024字节,第二次376字节。在第一次发送成功后,netty等              待数据时,B请求进行了数据发送,长度是200字节,此时暂存得byte数据成了1224字节,变量数据混乱。经查询有一种              线程本地变量,代码如下:

   private ThreadLocal<byte[]> clientBytes = new ThreadLocal<byte[]>(() =>  Array.Empty<byte>(), true);


ThreadLocal中第二个布尔值代表了是否可以在线程外操作该变量,数据操作通过value字段进行,示例如下:

  clientBytes.Value = clientBytes.Value.Concat(tempbytes).ToArray();

3.log4net配置的问题,因为调用的外部dll文件里的方法本身也配置了log4net,主程序在调用dll文件时每调用一次都会cretateRepository,导致重复多次调用时会报错,提示已存在该repositoryName,目前解决办法是不在dll插件里调用cretateRepository方法,但是会造成与主程序过多的耦合。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。