dotnetty使用过程中遇到的问题记录
以启动服务端为例,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); //} }
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方法,但是会造成与主程序过多的耦合。
- 点赞
- 收藏
- 关注作者
评论(0)