==>>点击查看本系列文章目录

目录

1. 消息监听器

2. 指令执行器

3. 消息发送器

4. 客户端工厂

5. 序列化工具

6. 通信主机

项目文件结构图

通信主机:

1. 消息监听器(黄色框)

这部分由 Netty 实现,Netty是一个异步且非阻塞的通信框架。TCP通信实现服务端和客户端的交互。

Netty 的简单描述如下:

客户端(调用方):负责发送要执行的指令。

服务端(接收方):分为主从线程。主线程负责接收指令,将指令存入缓存区中,等待执行完成后再通知客户端(非阻塞);

                从线程,有不止一个线程(异步),负责从缓存池中取出线程依次执行(按队列先后顺序执行),我们通过程序来决定先执行哪个,比如先解码,后执行,再编码。

上层接口:

    /// <summary>
/// 接受到消息的委托。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">接收到的消息。</param>
public delegate Task ReceivedDelegate(IMessageSender sender, TransportMessage message); /// <summary>
/// 一个抽象的消息监听者。
/// </summary>
public interface IMessageListener
{
/// <summary>
/// 接收到消息的事件。
/// </summary>
event ReceivedDelegate Received; /// <summary>
/// 触发接收到消息事件。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">接收到的消息。</param>
/// <returns>一个任务。</returns>
Task OnReceived(IMessageSender sender, TransportMessage message);
}

客户端:

/// <summary>
/// 消息监听者。
/// </summary>
public class DotNettyClientMessageListener : IMessageListener
{
#region Implementation of IMessageListener /// <summary>
/// 接收到消息的事件。
/// </summary>
public event ReceivedDelegate Received; /// <summary>
/// 触发接收到消息事件。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">接收到的消息。</param>
/// <returns>一个任务。</returns>
public async Task OnReceived(IMessageSender sender, TransportMessage message)
{
if (Received == null)
return;
await Received(sender, message);
} #endregion Implementation of IMessageListener
}

服务端:

    public class DotNettyServerMessageListener : IMessageListener, IDisposable
{
#region Field private readonly ILogger<DotNettyServerMessageListener> _logger;
private readonly ITransportMessageDecoder _transportMessageDecoder;
private readonly ITransportMessageEncoder _transportMessageEncoder;
private IChannel _channel; #endregion Field #region Constructor public DotNettyServerMessageListener(ILogger<DotNettyServerMessageListener> logger, ITransportMessageCodecFactory codecFactory)
{
_logger = logger;
_transportMessageEncoder = codecFactory.GetEncoder();
_transportMessageDecoder = codecFactory.GetDecoder();
} #endregion Constructor #region Implementation of IMessageListener public event ReceivedDelegate Received; /// <summary>
/// 触发接收到消息事件。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">接收到的消息。</param>
/// <returns>一个任务。</returns>
public async Task OnReceived(IMessageSender sender, TransportMessage message)
{
if (Received == null)
return;
await Received(sender, message);
} #endregion Implementation of IMessageListener public async Task StartAsync(EndPoint endPoint)
{
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug($"准备启动服务主机,监听地址:{endPoint}。"); IEventLoopGroup bossGroup = new MultithreadEventLoopGroup();
IEventLoopGroup workerGroup = new MultithreadEventLoopGroup();//Default eventLoopCount is Environment.ProcessorCount * 2
var bootstrap = new ServerBootstrap();
bootstrap
.Channel<TcpServerSocketChannel>()
.Option(ChannelOption.SoBacklog, )
.ChildOption(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
.Group(bossGroup, workerGroup)
.ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
{
var pipeline = channel.Pipeline;
pipeline.AddLast(new LengthFieldPrepender());
pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, , , , ));
pipeline.AddLast(new TransportMessageChannelHandlerAdapter(_transportMessageDecoder));
pipeline.AddLast(new ServerHandler(async (contenxt, message) =>
{
var sender = new DotNettyServerMessageSender(_transportMessageEncoder, contenxt);
await OnReceived(sender, message);
}, _logger));
}));
try
{
_channel = await bootstrap.BindAsync(endPoint);
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug($"服务主机启动成功,监听地址:{endPoint}。");
}
catch
{
_logger.LogError($"服务主机启动失败,监听地址:{endPoint}。 ");
}
} public void CloseAsync()
{
Task.Run(async () =>
{
await _channel.EventLoop.ShutdownGracefullyAsync();
await _channel.CloseAsync();
}).Wait();
} #region Implementation of IDisposable /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
Task.Run(async () =>
{
await _channel.DisconnectAsync();
}).Wait();
} #endregion Implementation of IDisposable #region Help Class private class ServerHandler : ChannelHandlerAdapter
{
private readonly Action<IChannelHandlerContext, TransportMessage> _readAction;
private readonly ILogger _logger; public ServerHandler(Action<IChannelHandlerContext, TransportMessage> readAction, ILogger logger)
{
_readAction = readAction;
_logger = logger;
} #region Overrides of ChannelHandlerAdapter public override void ChannelRead(IChannelHandlerContext context, object message)
{
Task.Run(() =>
{
var transportMessage = (TransportMessage)message;
_readAction(context, transportMessage);
});
} public override void ChannelReadComplete(IChannelHandlerContext context)
{
context.Flush();
} public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
{
context.CloseAsync();//客户端主动断开需要应答,否则socket变成CLOSE_WAIT状态导致socket资源耗尽
if (_logger.IsEnabled(LogLevel.Error))
_logger.LogError(null,exception, $"与服务器:{context.Channel.RemoteAddress}通信时发送了错误。");
} #endregion Overrides of ChannelHandlerAdapter
} #endregion Help Class
}

2. 指令执行器(红色框)

上图中只有服务端的实现,服务端接收到指令后会回调执行器中的过程。

客户端的时候需要在业务场景中来实现,根据业务不同,接收到服务端消息后执行的过程也不同。然后通过控制反转,由程序自动找到该过程。

上层接口:

    /// <summary>
/// 一个抽象的服务执行器。
/// </summary>
public interface IServiceExecutor
{
/// <summary>
/// 执行。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">调用消息。</param>
Task ExecuteAsync(IMessageSender sender, TransportMessage message);
}

实现类,代码中没有处理逻辑(服务发现、执行,后续有专题来谈),只有输出打印 "服务提供者接收到消息。" :

    public class HttpServiceExecutor : IServiceExecutor
{
#region Field private readonly ILogger<HttpServiceExecutor> _logger;
#endregion Field #region Constructor public HttpServiceExecutor(ILogger<HttpServiceExecutor> logger)
{
_logger = logger;
} #endregion Constructor #region Implementation of IServiceExecutor /// <summary>
/// 执行。
/// </summary>
/// <param name="sender">消息发送者。</param>
/// <param name="message">调用消息。</param>
public async Task ExecuteAsync(IMessageSender sender, TransportMessage message)
{
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("服务提供者接收到消息。");
return; }
#endregion Implementation of IServiceExecutor
}

3. 消息发送器(蓝色框)

将要发送的消息写入到通信管道中,服务端和客户端都有实现。

上层接口:

    /// <summary>
/// 一个抽象的发送者。
/// </summary>
public interface IMessageSender
{
/// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
Task SendAsync(TransportMessage message); /// <summary>
/// 发送消息并清空缓冲区。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
Task SendAndFlushAsync(TransportMessage message);
}

实现类基类:

    /// <summary>
/// 基于DotNetty的消息发送者基类。
/// </summary>
public abstract class DotNettyMessageSender
{
private readonly ITransportMessageEncoder _transportMessageEncoder; protected DotNettyMessageSender(ITransportMessageEncoder transportMessageEncoder)
{
_transportMessageEncoder = transportMessageEncoder;
} protected IByteBuffer GetByteBuffer(TransportMessage message)
{
var data = _transportMessageEncoder.Encode(message);
//var buffer = PooledByteBufferAllocator.Default.Buffer();
return Unpooled.WrappedBuffer(data);
}
}

服务端:

    /// <summary>
/// 基于DotNetty服务端的消息发送者。
/// </summary>
public class DotNettyServerMessageSender : DotNettyMessageSender, IMessageSender
{
private readonly IChannelHandlerContext _context; public DotNettyServerMessageSender(ITransportMessageEncoder transportMessageEncoder, IChannelHandlerContext context) : base(transportMessageEncoder)
{
_context = context;
} #region Implementation of IMessageSender /// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _context.WriteAsync(buffer);
} /// <summary>
/// 发送消息并清空缓冲区。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAndFlushAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _context.WriteAndFlushAsync(buffer);
} #endregion Implementation of IMessageSender
}

客户端:

/// <summary>
/// 基于DotNetty客户端的消息发送者。
/// </summary>
public class DotNettyMessageClientSender : DotNettyMessageSender, IMessageSender, IDisposable
{
private readonly IChannel _channel; public DotNettyMessageClientSender(ITransportMessageEncoder transportMessageEncoder, IChannel channel) : base(transportMessageEncoder)
{
_channel = channel;
} #region Implementation of IDisposable /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
Task.Run(async () =>
{
await _channel.DisconnectAsync();
}).Wait();
} #endregion Implementation of IDisposable #region Implementation of IMessageSender /// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _channel.WriteAndFlushAsync(buffer);
} /// <summary>
/// 发送消息并清空缓冲区。
/// </summary>
/// <param name="message">消息内容。</param>
/// <returns>一个任务。</returns>
public async Task SendAndFlushAsync(TransportMessage message)
{
var buffer = GetByteBuffer(message);
await _channel.WriteAndFlushAsync(buffer);
} #endregion Implementation of IMessageSender
}

4. 客户端工厂(绿色框)

为啥没有服务端工厂呢,因为服务端是由服务端主机(Host)直接创建的,主机直接调用监听器监听端口。既然我们重写了通信过程,就不能用微软原有的WebHost,后续会讲到如何搭建自己的主机。

客户端工厂用来创建客户端,然后与服务端主机通信。

上层接口:

    /// <summary>
/// 一个抽象的传输客户端工厂。
/// </summary>
public interface ITransportClientFactory
{
/// <summary>
/// 创建客户端。
/// </summary>
/// <param name="endPoint">终结点。</param>
/// <returns>传输客户端实例。</returns>
Task<ITransportClient> CreateClientAsync(EndPoint endPoint);
}
    /// <summary>
/// 一个抽象的传输客户端。
/// </summary>
public interface ITransportClient
{
/// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">远程调用消息模型。</param>
/// <returns>远程调用消息的传输消息。</returns>
Task SendAsync(TransportMessage transportMessage);
}

实现类:

    /// <summary>
/// 基于DotNetty的传输客户端工厂。
/// </summary>
public class DotNettyTransportClientFactory : ITransportClientFactory, IDisposable
{
#region Field private readonly ITransportMessageEncoder _transportMessageEncoder;
private readonly ITransportMessageDecoder _transportMessageDecoder;
private readonly ILogger<DotNettyTransportClientFactory> _logger;
private readonly IServiceExecutor _serviceExecutor;
private readonly ConcurrentDictionary<EndPoint, Lazy<Task<ITransportClient>>> _clients = new ConcurrentDictionary<EndPoint, Lazy<Task<ITransportClient>>>();
private readonly Bootstrap _bootstrap; private static readonly AttributeKey<IMessageSender> messageSenderKey = AttributeKey<IMessageSender>.ValueOf(typeof(DotNettyTransportClientFactory), nameof(IMessageSender));
private static readonly AttributeKey<IMessageListener> messageListenerKey = AttributeKey<IMessageListener>.ValueOf(typeof(DotNettyTransportClientFactory), nameof(IMessageListener));
private static readonly AttributeKey<EndPoint> origEndPointKey = AttributeKey<EndPoint>.ValueOf(typeof(DotNettyTransportClientFactory), nameof(EndPoint)); #endregion Field #region Constructor public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, ILogger<DotNettyTransportClientFactory> logger)
: this(codecFactory, logger, null)
{
} public DotNettyTransportClientFactory(ITransportMessageCodecFactory codecFactory, ILogger<DotNettyTransportClientFactory> logger, IServiceExecutor serviceExecutor)
{
_transportMessageEncoder = codecFactory.GetEncoder();
_transportMessageDecoder = codecFactory.GetDecoder();
_logger = logger;
_serviceExecutor = serviceExecutor;
_bootstrap = GetBootstrap();
_bootstrap.Handler(new ActionChannelInitializer<ISocketChannel>(c =>
{
var pipeline = c.Pipeline;
pipeline.AddLast(new LengthFieldPrepender());
pipeline.AddLast(new LengthFieldBasedFrameDecoder(int.MaxValue, , , , ));
pipeline.AddLast(new TransportMessageChannelHandlerAdapter(_transportMessageDecoder));
pipeline.AddLast(new DefaultChannelHandler(this));
}));
} #endregion Constructor #region Implementation of ITransportClientFactory /// <summary>
/// 创建客户端。
/// </summary>
/// <param name="endPoint">终结点。</param>
/// <returns>传输客户端实例。</returns>
public async Task<ITransportClient> CreateClientAsync(EndPoint endPoint)
{
var key = endPoint;
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug($"准备为服务端地址:{key}创建客户端。");
try
{
return await _clients.GetOrAdd(key
, k => new Lazy<Task<ITransportClient>>(async () =>
{
//客户端对象
var bootstrap = _bootstrap;
//异步连接返回channel
var channel = await bootstrap.ConnectAsync(k);
var messageListener = new DotNettyClientMessageListener();
//设置监听
channel.GetAttribute(messageListenerKey).Set(messageListener);
//实例化发送者
var messageSender = new DotNettyMessageClientSender(_transportMessageEncoder, channel);
//设置channel属性
channel.GetAttribute(messageSenderKey).Set(messageSender);
channel.GetAttribute(origEndPointKey).Set(k);
//创建客户端
var client = new DotNettyTransportClient(messageSender, messageListener, _logger, _serviceExecutor);
return client;
}
)).Value;//返回实例
}
catch
{
throw;
}
} #endregion Implementation of ITransportClientFactory #region Implementation of IDisposable /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
foreach (var client in _clients.Values.Where(i => i.IsValueCreated))
{
(client.Value as IDisposable)?.Dispose();
}
} #endregion Implementation of IDisposable private static Bootstrap GetBootstrap()
{
IEventLoopGroup group; var bootstrap = new Bootstrap(); group = new MultithreadEventLoopGroup();
bootstrap.Channel<TcpServerSocketChannel>(); bootstrap
.Channel<TcpSocketChannel>()
.Option(ChannelOption.TcpNodelay, true)
.Option(ChannelOption.Allocator, PooledByteBufferAllocator.Default)
.Group(group); return bootstrap;
} protected class DefaultChannelHandler : ChannelHandlerAdapter
{
private readonly DotNettyTransportClientFactory _factory; public DefaultChannelHandler(DotNettyTransportClientFactory factory)
{
this._factory = factory;
} #region Overrides of ChannelHandlerAdapter public override void ChannelInactive(IChannelHandlerContext context)
{
_factory._clients.TryRemove(context.Channel.GetAttribute(origEndPointKey).Get(), out var value);
} public override void ChannelRead(IChannelHandlerContext context, object message)
{
var transportMessage = message as TransportMessage; var messageListener = context.Channel.GetAttribute(messageListenerKey).Get();
var messageSender = context.Channel.GetAttribute(messageSenderKey).Get();
messageListener.OnReceived(messageSender, transportMessage);
} #endregion Overrides of ChannelHandlerAdapter
}
}
    /// <summary>
/// 一个默认的传输客户端实现。
/// </summary>
public class DotNettyTransportClient : ITransportClient, IDisposable
{
#region Field private readonly IMessageSender _messageSender;
private readonly IMessageListener _messageListener;
private readonly ILogger _logger;
private readonly IServiceExecutor _serviceExecutor; #endregion Field #region Constructor public DotNettyTransportClient(IMessageSender messageSender, IMessageListener messageListener, ILogger logger, IServiceExecutor serviceExecutor)
{
_messageSender = messageSender;
_messageListener = messageListener;
_logger = logger;
_serviceExecutor = serviceExecutor;
messageListener.Received += MessageListener_Received;
} #endregion Constructor #region Implementation of ITransportClient /// <summary>
/// 发送消息。
/// </summary>
/// <param name="message">远程调用消息模型。</param>
/// <returns>远程调用消息的传输消息。</returns>
public async Task SendAsync(TransportMessage transportMessage)
{
try
{
if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug("准备发送消息。"); try
{
//发送
await _messageSender.SendAndFlushAsync(transportMessage);
}
catch (Exception exception)
{
throw new Exception("与服务端通讯时发生了异常。", exception);
} if (_logger.IsEnabled(LogLevel.Debug))
_logger.LogDebug("消息发送成功。"); }
catch (Exception exception)
{
if (_logger.IsEnabled(LogLevel.Error))
_logger.LogError(null,exception, "消息发送失败。");
throw;
}
} #endregion Implementation of ITransportClient #region Implementation of IDisposable /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
(_messageSender as IDisposable)?.Dispose();
(_messageListener as IDisposable)?.Dispose();
} #endregion Implementation of IDisposable #region Private Method private async Task MessageListener_Received(IMessageSender sender, TransportMessage message)
{
if (_logger.IsEnabled(LogLevel.Trace))
_logger.LogTrace("服务消费者接收到消息。"); if (_serviceExecutor != null)
await _serviceExecutor.ExecuteAsync(sender, message);
} #endregion Private Method
}

5. 序列化工具(白色框)

上节中我们用MessagePack实现了序列化与反序列化,本节为通信,自然离不开消息序列化。

需要继承自 DotNetty.Transport.Channels.ChannelHandlerAdapter,才能被 netty 调用:

public class TransportMessageChannelHandlerAdapter : ChannelHandlerAdapter
{
private readonly ITransportMessageDecoder _transportMessageDecoder; public TransportMessageChannelHandlerAdapter(ITransportMessageDecoder transportMessageDecoder)
{
_transportMessageDecoder = transportMessageDecoder;
} #region Overrides of ChannelHandlerAdapter public override void ChannelRead(IChannelHandlerContext context, object message)
{
var buffer = (IByteBuffer)message;
var data = new byte[buffer.ReadableBytes];
buffer.ReadBytes(data);
var transportMessage = _transportMessageDecoder.Decode(data);
context.FireChannelRead(transportMessage);
ReferenceCountUtil.Release(buffer);
} #endregion Overrides of ChannelHandlerAdapter
}

6. 通信主机(黄色框)

用于启动通信监听端口

内部包含消息监听器(_serverMessageListener)和消息执行器(_serverMessageListener)。

接口:

public interface ITransportHost : IDisposable
{
/// <summary>
/// 启动主机。
/// </summary>
/// <param name="endPoint">主机终结点。</param>
/// <returns>一个任务。</returns>
Task StartAsync(EndPoint endPoint); /// <summary>
/// 启动主机。
/// </summary>
/// <param name="endPoint">ip地址。</param>
Task StartAsync(string ip, int port);
}

实现类:

public class DotNettyTransportHost : ITransportHost
{
#region Field private IServiceExecutor _serviceExecutor;
public IServiceExecutor ServiceExecutor { get => _serviceExecutor; }
private readonly Func<EndPoint, Task<IMessageListener>> _messageListenerFactory;
private IMessageListener _serverMessageListener; #endregion Field public DotNettyTransportHost(Func<EndPoint, Task<IMessageListener>> messageListenerFactory, IServiceExecutor serviceExecutor)
{
_messageListenerFactory = messageListenerFactory;
_serviceExecutor = serviceExecutor;
} /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
(_serverMessageListener as IDisposable)?.Dispose();
} /// <summary>
/// 启动主机。
/// </summary>
/// <param name="endPoint">主机终结点。</param>
/// <returns>一个任务。</returns>
public async Task StartAsync(EndPoint endPoint)
{
if (_serverMessageListener != null)
return;
_serverMessageListener = await _messageListenerFactory(endPoint);
_serverMessageListener.Received += MessageListener_Received;
} public async Task StartAsync(string ip, int port)
{
if (_serverMessageListener != null)
return;
_serverMessageListener = await _messageListenerFactory(new IPEndPoint(IPAddress.Parse(ip), port));
_serverMessageListener.Received += MessageListener_Received;
//await StartAsync(new IPEndPoint(IPAddress.Parse(ip), port));
} /// <summary>
/// 监听并回调
/// </summary>
/// <param name="sender">消息发送器</param>
/// <param name="message">监听到的消息</param>
/// <returns></returns>
private async Task MessageListener_Received(IMessageSender sender, TransportMessage message)
{
await _serviceExecutor.ExecuteAsync(sender, message);
}
}

(七)分布式通信----Netty实现NIO通信的更多相关文章

  1. Java NIO通信框架在电信领域的实践

    [http://www.codeceo.com/article/java-nio-communication.html]   华为电信软件技术架构演进 Java NIO框架在技术变迁中起到的关键作用 ...

  2. 为什么选择Netty作为基础通信框架?

    在开始之前,我先讲一个亲身经历的故事:曾经有两个项目组同时用到了NIO编程技术,一个项目组选择自己开发NIO服务端,直接使用JDK原生的API,结果两个多月过去了,他们的NIO服务端始终无法稳定,问题 ...

  3. 使用netty编写IM通信界面

    前驱知识 WebSocket 维基百科: WebSocket是一种在单个TCP连接上进行全双工通信的协议.WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补 ...

  4. 【转】跟我学Kafka之NIO通信机制

    from:云栖社区 玛德,今天又被人打脸了,小看人,艹,确实,相对比起来,在某些方面差一点,,,,该好好捋捋了,强化下短板,规划下日程,,,引以为耻,铭记于心. 跟我学Kafka之NIO通信机制   ...

  5. Hadoop源码解析之 rpc通信 client到server通信

    rpc是Hadoop分布式底层通信的基础,无论是client和namenode,namenode和datanode,以及yarn新框架之间的通信模式等等都是采用的rpc方式. 下面我们来概要分析一下H ...

  6. 漫谈Java IO之 Netty与NIO服务器

    前面介绍了基本的网络模型以及IO与NIO,那么有了NIO来开发非阻塞服务器,大家就满足了吗?有了技术支持,就回去追求效率,因此就产生了很多NIO的框架对NIO进行封装--这就是大名鼎鼎的Netty. ...

  7. 2.Netty 与 NIO 之前世今生

      2.Netty 与 NIO 之前世今生 本文围绕一下几点阐述: 1. NIO 的核心组件 Buffer.Selector.Channel. 2.何谓多路复用? 3.Netty 支持的功能与特性. ...

  8. Netty(二)Netty 与 NIO 之前世今生

    2.1 Java NIO 三件套 在 NIO 中有几个核心对象需要掌握:缓冲区(Buffer).选择器(Selector).通道(Channel). 2.1.1 缓冲区 Buffer 1.Buffer ...

  9. JAVA基础知识之网络编程——-TCP/IP协议,socket通信,服务器客户端通信demo

    OSI模型分层 OSI模型是指国际标准化组织(ISO)提出的开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它将网络分为七 ...

随机推荐

  1. 基于SDN网络的负载均衡研究与实现

    为什么需要软件定义网络 1.网络缺乏可扩展性,创新正在停滞不前.   我们最新的研究发现,几乎每两个组织中就有一个认为需要将网络功能扩展为采用SDN的主要业务触发因素,而不是其他催化剂.这一统计数据一 ...

  2. 完整使用JDBC访问数据库

    Connection con = null; PreparedStatement statement = null; ResultSet res = null; List<Student> ...

  3. <<Modern CMake>> 翻译 2.3 与代码通信

    <<Modern CMake>> 翻译 2.3 与代码通信 配置文件 CMake 允许您使用代码通过 configure_file 存取 CMake 变量. 此命令复制一个文件 ...

  4. handlerMapping的初始化以及查找handler

    前提:HttpServletBean初始化了一些servlet配置,接着FrameWorkServlet创建了WebApplicationContext,最后DispatcherServlet初始化一 ...

  5. Win10系统下安装labelme,json文件批量转化

    一.安装环境:windows10,anaconda3,python3.6         由于框架maskrcnn需要json数据集,在没安装labelme环境和跑深度学习之前,我安装的是anacon ...

  6. Python(简单图形和文件处理)编程

    Python确实是一门很简洁而且功能有强大的语言,我觉得开始学习很容易理解,说到熟练和精通还是不容易的,还需不断学习. 从最基础的语法学习,有些部分各种语言是相同的,让人很好理解.编程也是从最简单语法 ...

  7. java使用栈计算后缀表达式

    package com.nps.base.xue.DataStructure.stack.utils; import java.util.Scanner; import java.util.Stack ...

  8. 使用钉钉对接禅道的bug系统,实现禅道提的bug实时在钉钉提醒并艾特对应的开发人员处理

    现在公司测试中有一个痛点是每次测试人员提完bug后,需要定期去提醒开发人员查看禅道的bug记录及修复bug. 导致测试人员在项目测试中不仅要测试整个软件,还要负起实时监督提醒功能的“保姆角色”,身心疲 ...

  9. ArchSummit分享 | 高德地图App架构演化与实践

    讲师介绍 郝仁杰,高德地图无线开发专家.在7月13日落幕的2019年ArchSummit峰会上就高德地图近几年的App架构演化和实践进行了分享. 背景概述 高德是国内领先的数字地图内容.导航和位置服务 ...

  10. DES、3DES、AES、PBE对称加密算法实现及应用

    1.对称加密算法概述 对称加密算法是应用较早的加密算法,技术成熟.在对称加密算法中,数据发信方将明文和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去.收信方收到密文后,若想解读原文 ...