ReferenceCountExchangeClient:将请求交HeaderExchangeClient处理,不进行任何其他操作。
- public ResponseFuture request(Object request) throws RemotingException {
- return client.request(request);
- }
HeaderExchangeClient:提供心跳检查功能;将send、request、close等事件转由HeaderExchangeChannel处理,HeaderExchangeChannel对象中的Channel为所选的NIO框架对应的client对象;以request为例,调用流程如下:HeaderExchangeClient.request(Object request)->HeaderExchangeChannel.request(Object request)->(NettyClient)AbstractPeer.send(Object message)->(NettyClient)AbstractClient.send(Object message,boolean sent)。
- public ResponseFuture request(Object request) throws RemotingException {
- return channel.request(request);//HeaderExchangeChannel
- }
HeaderExchangeChannel:主要是完成同步转异步,在request(Object request,int timeout)方法中,将请求转换成Request对象,将请求消息设置到data属性上,构建DefaultFuture对象,调用NIO框架对应的Client对象(默认NettyClient)的send方法将消息发送出去,返回DefultFuture对象。
- public ResponseFuture request(Object request, int timeout) throws RemotingException {
- if (closed) {
- throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
- }
- // create request.
- Request req = new Request();
- req.setVersion("2.0.0");
- req.setTwoWay(true);
- req.setData(request);
- DefaultFuture future = new DefaultFuture(channel, req, timeout);
- try{
- channel.send(req);
- }catch (RemotingException e) {
- future.cancel();
- throw e;
- }
- return future;
- }
NettyClient:完成消息的发送。在调用链的最后一个方法AbstractClient.send(Object message, boolean sent)中,首先通过调用NettyClient.getChannel()获取NettyChannel对象,在构建对象时封装了NIOSocketChannel对象(在初始化NettyClient对象时,根据nettyclient和server端建立连接时获取的socket通道)、统一数据模型URL以及channelHandler对象(NettyClient对象自身),然后调用NettyChannel对象的send方法,将Request消息写入NIOSocketChannel通道中,完成消息发送。
- public void send(Object message, boolean sent) throws RemotingException {//AbstractClient
- if (send_reconnect && !isConnected()){
- connect();
- }
- Channel channel = getChannel();
- //TODO getChannel返回的状态是否包含null需要改进
- if (channel == null || ! channel.isConnected()) {
- throw new RemotingException(this, "message can not send, because channel is closed . url:" + getUrl());
- }
- channel.send(message, sent);
- }
- @Override
- protected com.sitech.hsf.remoting.Channel getChannel() {//nettyclient
- Channel c = channel;
- if (c == null || ! c.isConnected())
- return null;
- return NettyChannel.getOrAddChannel(c, getUrl(), this);
- }
- public void send(Object message, boolean sent) throws RemotingException {//NettyChannel
- super.send(message, sent);
- boolean success = true;
- int timeout = 0;
- try {//调用Netty框架
- ChannelFuture future = channel.write(message);
- if (sent) {//sent=true等待发送失败将抛出异常,false不等待消息发出,将消息放入IO队列,即刻返回。
- timeout = getUrl().getPositiveParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
- success = future.await(timeout);
- }
- Throwable cause = future.getCause();
- if (cause != null) {
- throw cause;
- }
- } catch (Throwable e) {
- throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress() + ", cause: " + e.getMessage(), e);
- }
- if(! success) {
- throw new RemotingException(this, "Failed to send message " + message + " to " + getRemoteAddress()
- + "in timeout(" + timeout + "ms) limit");
- }
- }
HeaderExchangeServer:提供心跳检查功能;启动心跳监测线程池,该线程初始化了一个线程,在线程中调用类HeartBeatTask进行心跳检查,HeartBeatTask处理心跳的规则:
(1)若通道的最新的写入时间或者最新的读取时间与当前时间相比,已经超过了心跳间隔时间,则发送心跳请求;
(2)如果通道的最新的读取时间与当前时间相比,已经超过了心跳的超时时间,对于客户端来说则重连,对于服务端来说则关闭通道。
- public HeaderExchangeServer(Server server) {
- if (server == null) {
- throw new IllegalArgumentException("server == null");
- }
- this.server = server;
- this.heartbeat = server.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);//
- this.heartbeatTimeout = server.getUrl().getParameter(Constants.HEARTBEAT_TIMEOUT_KEY, heartbeat * 3);
- if (heartbeatTimeout < heartbeat * 2) {
- throw new IllegalStateException("heartbeatTimeout < heartbeatInterval * 2");
- }
- startHeatbeatTimer();
- }
- private void startHeatbeatTimer() {//HeaderExchangeServer
- stopHeartbeatTimer();
- if (heartbeat > 0) {
- heatbeatTimer = scheduled.scheduleWithFixedDelay(
- new HeartBeatTask( new HeartBeatTask.ChannelProvider() {
- public Collection<Channel> getChannels() {
- return Collections.unmodifiableCollection(
- HeaderExchangeServer.this.getChannels() );
- }
- }, heartbeat, heartbeatTimeout),
- heartbeat, heartbeat,TimeUnit.MILLISECONDS);
- }
- }
如果心跳为0,不执行心跳检测功能。
- public void run() {//HeartBeatTask
- try {
- long now = System.currentTimeMillis();//获取当前时间
- for ( Channel channel : channelProvider.getChannels() ) {
- if (channel.isClosed()) {//已经关闭了
- continue;
- }
- try {
- //最后一次读的时间戳
- Long lastRead = ( Long ) channel.getAttribute(
- HeaderExchangeHandler.KEY_READ_TIMESTAMP );
- //最后一次写的时间戳
- Long lastWrite = ( Long ) channel.getAttribute(
- HeaderExchangeHandler.KEY_WRITE_TIMESTAMP );
- //如果当前时间距离最后一次写或读超过一个心跳时间
- if ( ( lastRead != null && now - lastRead > heartbeat )
- || ( lastWrite != null && now - lastWrite > heartbeat ) ) {
- Request req = new Request();
- req.setVersion( "2.0.0" );
- req.setTwoWay( true );
- req.setEvent( Request.HEARTBEAT_EVENT );
- channel.send( req );
- if ( logger.isDebugEnabled() ) {
- logger.debug( "Send heartbeat to remote channel " + channel.getRemoteAddress()
- + ", cause: The channel has no data-transmission exceeds a heartbeat period: " + heartbeat + "ms" );
- }
- }
- //如果上一次读距离现在已经超过心路超时时长,尝试重连
- if ( lastRead != null && now - lastRead > heartbeatTimeout ) {
- logger.warn( "Close channel " + channel
- + ", because heartbeat read idle time out: " + heartbeatTimeout + "ms" );
- if (channel instanceof Client) {
- try {
- ((Client)channel).reconnect();
- }catch (Exception e) {
- //do nothing
- }
- } else {
- channel.close();
- }
- }
- } catch ( Throwable t ) {
- logger.warn( "Exception when heartbeat to remote channel " + channel.getRemoteAddress(), t );
- }
- }
- } catch ( Throwable t ) {
- logger.warn( "Unhandled exception when heartbeat, cause: " + t.getMessage(), t );
- }
- }
在起动NettyClient和NettyServer连接时,都添加了一个HeartbeatHandler
- public void received(Channel channel, Object message) throws RemotingException {
- setReadTimestamp(channel);
- if (isHeartbeatRequest(message)) {//如果是心跳请求
- Request req = (Request) message;
- if (req.isTwoWay()) {
- Response res = new Response(req.getId(), req.getVersion());
- res.setEvent(Response.HEARTBEAT_EVENT);
- channel.send(res);
- if (logger.isInfoEnabled()) {
- int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);
- if(logger.isDebugEnabled()) {
- logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress()
- + ", cause: The channel has no data-transmission exceeds a heartbeat period"
- + (heartbeat > 0 ? ": " + heartbeat + "ms" : ""));
- }
- }
- }
- return;
- }
- if (isHeartbeatResponse(message)) {//如果是心跳响应
- if (logger.isDebugEnabled()) {
- logger.debug(
- new StringBuilder(32)
- .append("Receive heartbeat response in thread ")
- .append(Thread.currentThread().getName())
- .toString());
- }
- return;
- }
- handler.received(channel, message);
- }
多线程并发请求与单一长连接
- public ResponseFuture request(Object request, int timeout) throws RemotingException {//HeaderExchangeChannel.request
- if (closed) {
- throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
- }
- // create request.
- Request req = new Request();
- req.setVersion("2.0.0");
- req.setTwoWay(true);
- req.setData(request);
- DefaultFuture future = new DefaultFuture(channel, req, timeout);
- try{
- channel.send(req);
- }catch (RemotingException e) {
- future.cancel();
- throw e;
- }
- return future;
- }