cn.tom.transport.aio.AioClient Maven / Gradle / Ivy
The newest version!
package cn.tom.transport.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.tom.kit.ThreadPool;
import cn.tom.kit.ThreadPool.DefaultThreadFactory;
import cn.tom.transport.Client;
import cn.tom.transport.Id;
import cn.tom.transport.IoAdaptor;
import cn.tom.transport.Ticket;
import cn.tom.transport.Messager.MessageCallback;
public class AioClient implements Client{
private static final Logger log = LoggerFactory.getLogger(AioClient.class);
protected final String brokerAddress;
private int readTimeout = 20000;
private String host = "127.0.0.1";
private int port = 15555;
private IoAdaptor ioAdaptor;
public AioSession session;
public AioClient(String address) throws IOException {
this.brokerAddress = address;
String[] blocks = address.split("[:]");
if (blocks.length > 2) {
throw new IllegalArgumentException("Illegal address: " + address);
}
String host = blocks[0].trim();
this.host = host;
int port = 15555;
if (blocks.length > 1) {
port = Integer.valueOf(blocks[1].trim());
}
this.port = port;
}
public AioClient(String host, int port) {
this.host = host;
this.port = port;
this.brokerAddress = String.format("%s:%d", host, port);
}
@Override
public void heartbeat() {
if(hasConnected()){
ioAdaptor.heartbeat(session);
}
}
@Override
public void doConnect() throws IOException {
// client 至少 2个线程, 1个线程的话可能频繁写没有线程读死锁
AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withFixedThreadPool(2, new DefaultThreadFactory("AioClient-pool-"));
AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open(asynchronousChannelGroup);
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
socketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
session = new AioSession(ioAdaptor, socketChannel);
ConnectedHandler connectedCompletionHandler = new ConnectedHandler();
InetSocketAddress socketAddress = new InetSocketAddress(this.host, this.port);
socketChannel.connect(socketAddress, session, connectedCompletionHandler);
session.waitToConnect(20000);
}
/**
* 异步访问, client少量, 重点在于处理与回调
* write 不等待加大了 buffer读写区
*/
@Override
public void invokeAsync(T req, MessageCallback callback) throws IOException {
connectIfNeed();
ioAdaptor.createTicket(req, readTimeout*10, callback);
session.write(req);
}
/**
* 同步访问, 增加client数量, 性能加大,
* 看buffer的大小,由于同步, 多client 加大了buffer读写区
*/
@Override
public T invokeSync(T req) throws IOException, InterruptedException {
return invokeSync(req, readTimeout);
}
public T invokeSync(T req, int timeout) throws IOException, InterruptedException {
Ticket ticket = null;
try {
connectIfNeed();
ticket = ioAdaptor.createTicket(req, timeout, null);
session.write(req);
if(!ticket.await(timeout, TimeUnit.MILLISECONDS)){
if(!session.isActive()){
throw new IOException("Connection reset by peer");
} else {
return null;
}
}
return (T) ticket.response();
} finally{
if(ticket != null){
ioAdaptor.removeTicket(ticket.getId());
}
}
}
@Override
public void send(T msg) throws IOException {
connectIfNeed();
session.write(msg);
}
@Override
public void setIoAdaptor(IoAdaptor ioAdaptor) {
this.ioAdaptor = ioAdaptor;
}
public void connectIfNeed() throws IOException {
if (!this.hasConnected()) {
synchronized (brokerAddress) {
if(!this.hasConnected()){
doConnect();
heartbeat();
}
}
}
}
@Override
public boolean hasConnected() {
return session != null && session.isActive();
}
@Override
public void close() throws IOException {
if (this.session != null) {
this.session.close();
}
ThreadPool.getAioPool().shutdown();
}
}