All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.acgist.snail.net.TcpMessageHandler Maven / Gradle / Ivy

package com.acgist.snail.net;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.acgist.snail.net.codec.IMessageCodec;
import com.acgist.snail.system.config.SystemConfig;
import com.acgist.snail.system.exception.NetException;
import com.acgist.snail.utils.IoUtils;

/**
 * TCP消息代理
 * 
 * @author acgist
 * @since 1.0.0
 */
public abstract class TcpMessageHandler implements CompletionHandler, IMessageHandler {

	private static final Logger LOGGER = LoggerFactory.getLogger(TcpMessageHandler.class);
	
	/**
	 * 是否关闭
	 */
	private boolean close = false;
	/**
	 * Socket
	 */
	protected AsynchronousSocketChannel socket;
	/**
	 * 消息处理器
	 */
	protected IMessageCodec messageCodec;
	
	/**
	 * 

收到消息

*

使用消息处理器处理消息,如果没有实现消息处理器,请重写该方法。

*/ public void onReceive(ByteBuffer buffer) throws NetException { if(this.messageCodec == null) { throw new NetException("请实现消息处理器"); } this.messageCodec.decode(buffer); } /** * 消息代理 */ public void handle(AsynchronousSocketChannel socket) { this.socket = socket; this.loopMessage(); } @Override public boolean available() { return !this.close && this.socket != null; } @Override public void send(String message, String charset) throws NetException { if(this.messageCodec == null) { throw new NetException("请实现消息处理器"); } send(this.charset(this.messageCodec.encode(message), charset)); } @Override public void send(ByteBuffer buffer, int timeout) throws NetException { if(!available()) { LOGGER.debug("TCP消息发送失败:Socket不可用"); return; } if(buffer.position() != 0) { buffer.flip(); } if(buffer.limit() == 0) { LOGGER.warn("TCP消息发送失败:{}", buffer); return; } synchronized (this.socket) { try { final Future future = this.socket.write(buffer); /* * 阻塞线程:等待发送完成,防止多线程同时写导致WritePendingException。 * 超时时间:超时异常会导致数据并没有发送完成而释放了锁,从而引起一连串的WritePendingException异常。 * 建议:除了第一条消息以外的所有消息都不要使用超时时间。 */ int size = 0; if(timeout <= TIMEOUT_NONE) { size = future.get(); } else { size = future.get(timeout, TimeUnit.SECONDS); } if(size <= 0) { LOGGER.warn("TCP消息发送失败:{}", size); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new NetException(e); } catch (TimeoutException | ExecutionException e) { throw new NetException(e); } } } @Override public InetSocketAddress remoteSocketAddress() { try { return (InetSocketAddress) this.socket.getRemoteAddress(); } catch (IOException e) { LOGGER.error("TCP获取远程服务地址异常", e); } return null; } @Override public void close() { this.close = true; IoUtils.close(this.socket); } @Override public void completed(Integer result, ByteBuffer buffer) { if (result == null) { this.close(); } else if(result == -1) { // 服务端关闭 this.close(); } else if(result == 0) { // 空轮询 LOGGER.debug("TCP消息接收失败(长度):{}", result); } else { try { onReceive(buffer); } catch (NetException e) { LOGGER.error("TCP消息接收异常", e); } } if(available()) { loopMessage(); } else { LOGGER.debug("TCP消息代理跳出循环:{}", result); } } @Override public void failed(Throwable ex, ByteBuffer buffer) { LOGGER.error("TCP消息处理异常", ex); } /** * 消息循环读取 */ private void loopMessage() { if(available()) { final ByteBuffer buffer = ByteBuffer.allocate(SystemConfig.TCP_BUFFER_LENGTH); this.socket.read(buffer, buffer, this); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy