I want to write a netty based client. It should have method public String send(String msg); which should return response from the server or some future - doesen't matter. Also it should be multithreaded. Like this:
public class Client {
public static void main(String[] args) throws InterruptedException {
Client client = new Client();
}
private Channel channel;
public Client() throws InterruptedException {
EventLoopGroup loopGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(loopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder()).
addLast(new StringEncoder()).
addLast(new ClientHandler());
}
});
channel = b.connect("localhost", 9091).sync().channel();
}
public String sendMessage(String msg) {
channel.writeAndFlush(msg);
return ??????????;
}
}
And I don't get how can I retrieve response from server after I invoke writeAndFlush(); What should I do?
Also I use Netty 4.0.18.Final
Returning a Future<String> for the method is simple, we are going to implement the following method signature:
public Futute<String> sendMessage(String msg) {
The is relatively easy to do when you are known with the async programming structures. To solve the design problem, we are going to do the following steps:
When a message is written, add a Promise<String> to a ArrayBlockingQueue<Promise>
This will serve as a list of what messages have recently been send, and allows us to change our Future<String> objects return result.
When a message arrives back into the handler, resolve it against the head of the Queue
This allows us to get the correct future to change.
Update the state of the Promise<String>
We call promise.setSuccess() to finally set the state on the object, this will propagate back to the future object.
Example code
public class ClientHandler extends SimpleChannelInboundHandler<String> {
private ChannelHandlerContext ctx;
private BlockingQueue<Promise<String>> messageList = new ArrayBlockingQueue<>(16);
#Override
public void channelActive(ChannelHandlerContext ctx) {
super.channelActive(ctx);
this.ctx = ctx;
}
#Override
public void channelInactive(ChannelHandlerContext ctx) {
super.channelInactive(ctx);
synchronized(this){
Promise<String> prom;
while((prom = messageList.poll()) != null)
prom.setFailure(new IOException("Connection lost"));
messageList = null;
}
}
public Future<String> sendMessage(String message) {
if(ctx == null)
throw new IllegalStateException();
return sendMessage(message, ctx.executor().newPromise());
}
public Future<String> sendMessage(String message, Promise<String> prom) {
synchronized(this){
if(messageList == null) {
// Connection closed
prom.setFailure(new IllegalStateException());
} else if(messageList.offer(prom)) {
// Connection open and message accepted
ctx.writeAndFlush(message).addListener();
} else {
// Connection open and message rejected
prom.setFailure(new BufferOverflowException());
}
return prom;
}
}
#Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) {
synchronized(this){
if(messageList != null) {
messageList.poll().setSuccess(msg);
}
}
}
}
Documentation breakdown
private ChannelHandlerContext ctx;
Used to store our reference to the ChannelHandlerContext, we use this so we can create promises
private BlockingQueue<Promise<String>> messageList = new ArrayBlockingQueue<>();
We keep the past messages in this list so we can change the result of the future
public void channelActive(ChannelHandlerContext ctx)
Called by netty when the connection becomes active. Init our variables here.
public void channelInactive(ChannelHandlerContext ctx)
Called by netty when the connection becomes inactive, either due to error or normal connection close.
protected void messageReceived(ChannelHandlerContext ctx, String msg)
Called by netty when a new message arrives, here pick out the head of the queue, and then we call setsuccess on it.
Warning advise
When using futures, there is 1 thing you need to lookout for, do not call get() from 1 of the netty threads if the future isn't done yet, failure to follow this simple rule will either result in a deadlock or a BlockingOperationException.
You can find the sample in netty project.
We can save the result into the last handler's custom fields. In the following code, it is handler.getFactorial() that is what we want.
refer to http://www.lookatsrc.com/source/io/netty/example/factorial/FactorialClient.java?a=io.netty:netty-all
FactorialClient.java
public final class FactorialClient {
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
static final int COUNT = Integer.parseInt(System.getProperty("count", "1000"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new FactorialClientInitializer(sslCtx));
// Make a new connection.
ChannelFuture f = b.connect(HOST, PORT).sync();
// Get the handler instance to retrieve the answer.
FactorialClientHandler handler =
(FactorialClientHandler) f.channel().pipeline().last();
// Print out the answer.
System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
} finally {
group.shutdownGracefully();
}
}
}
public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> {
private ChannelHandlerContext ctx;
private int receivedMessages;
private int next = 1;
final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
public BigInteger getFactorial() {
boolean interrupted = false;
try {
for (;;) {
try {
return answer.take();
} catch (InterruptedException ignore) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
this.ctx = ctx;
sendNumbers();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, final BigInteger msg) {
receivedMessages ++;
if (receivedMessages == FactorialClient.COUNT) {
// Offer the answer after closing the connection.
ctx.channel().close().addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
boolean offered = answer.offer(msg);
assert offered;
}
});
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private void sendNumbers() {
// Do not send more than 4096 numbers.
ChannelFuture future = null;
for (int i = 0; i < 4096 && next <= FactorialClient.COUNT; i++) {
future = ctx.write(Integer.valueOf(next));
next++;
}
if (next <= FactorialClient.COUNT) {
assert future != null;
future.addListener(numberSender);
}
ctx.flush();
}
private final ChannelFutureListener numberSender = new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
sendNumbers();
} else {
future.cause().printStackTrace();
future.channel().close();
}
}
};
}
Calling channel.writeAndFlush(msg); already returns a ChannelFuture. To handle the result of this method call, you could add a listener to the future like this:
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
// Perform post-closure operation
// ...
}
});
(this is taken from the Netty documentation see: Netty doc)
Related
I am writing a minecraft server in java from scratch for private reasons.
I am new to the netty api so please explain how I can fix it
My problem is pretty simple my server waits for a connection then reads data from that connection but it never reads the then bit of info
https://wiki.vg/Server_List_Ping
I followed that and everything goes well up until the request packet which my server never reads it?
I don't know what the problem is I think it's because its closing the connection but I have no idea how to stop that
Here's the code
public class DataHandler extends SimpleChannelInboundHandler {
public void initChannel(NioServerSocketChannel nioServerSocketChannel) throws Exception {
try {
System.out.println("Data Handler");
}catch (Exception e) {
}
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("[DEBUG] Read complete");
//ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
// .addListener(ChannelFutureListener.CLOSE);
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("Data Handler active");
ctx.channel().read();
//ctx.pipeline().addLast("encoder",new Encoder());
//ctx.fireChannelActive();
}
private int pos = 0;
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
//ByteBuf packet = buf.readBytes(length);
int length = readVarInt(buf);
int ID = readVarInt(buf);
System.out.println("[DEBUG] PACKET ID: "+ID);
Packet packet = PacketUtil.createPacket(ID,length,buf,ctx);
packet.readBuf();
Object ran = null;
//super.channelRead(ctx, msg);
}
#Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
System.out.println("Test");
}
}
There is some trial and error comments in there I did not know if I should have left them in
Heres the main class
public class Server {
private int port;
public void run() throws IOException {
port = 25565;
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup threadGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(mainGroup, threadGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new DataHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 5)
.option(ChannelOption.AUTO_READ,true)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture channelFuture = b.localAddress(port).bind().sync();
System.out.println(String.format("Started on port %d", port));
System.out.println("Registering packets");
PacketUtil.registerPackets();
}catch(InterruptedException e) {
}
}
}
I'm learning Netty and prototyping a simple app which sends an object over TCP. My issue is that when I call Channel.write from the server side with my message, it doesn't seem to reach the handlers in the pipeline. When I send a message from client to server, it works as expected.
Here's the code.
The server:
public class Main {
private int serverPort;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private ServerBootstrap boot;
private ChannelFuture future;
private SomeDataChannelDuplexHandler duplex;
private Channel ch;
public Main(int serverPort) {
this.serverPort = serverPort;
}
public void initialise() {
boot = new ServerBootstrap();
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
boot.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(0, 0, 2));
// Inbound
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 0));
ch.pipeline().addLast(new SomeDataDecoder());
// Outbound
ch.pipeline().addLast(new LengthFieldPrepender(2));
ch.pipeline().addLast(new SomeDataEncoder());
// In-Out
ch.pipeline().addLast(new SomeDataChannelDuplexHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
}
public void sendMessage() {
SomeData fd = new SomeData("hello", "localhost", 1234);
ChannelFuture future = ch.writeAndFlush(fd);
future.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
System.out.println("send error: " + future.cause().toString());
} else {
System.out.println("send message ok");
}
}
});
}
public void startServer(){
try {
future = boot.bind(serverPort)
.sync()
.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
ch = future.channel();
}
});
} catch (InterruptedException e) {
// log failure
}
}
public void stopServer() {
workerGroup.shutdownGracefully()
.addListener(e -> System.out.println("workerGroup shutdown"));
bossGroup.shutdownGracefully()
.addListener(e -> System.out.println("bossGroup shutdown"));
}
public static void main(String[] args) throws InterruptedException {
Main m = new Main(5000);
m.initialise();
m.startServer();
final Scanner scanner = new Scanner(System.in);
System.out.println("running.");
while (true) {
final String input = scanner.nextLine();
if ("q".equals(input.trim())) {
break;
} else {
m.sendMessage();
}
}
scanner.close();
m.stopServer();
}
}
The duplex channel handler:
public class SomeDataChannelDuplexHandler extends ChannelDuplexHandler {
#Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("duplex channel active");
ctx.fireChannelActive();
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("duplex channelRead");
if (msg instanceof SomeData) {
SomeData sd = (SomeData) msg;
System.out.println("received: " + sd);
} else {
System.out.println("some other object");
}
ctx.fireChannelRead(msg);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
if (evt instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) evt;
if (event.state() == IdleState.ALL_IDLE) { // idle for no read and write
System.out.println("idle: " + event.state());
}
}
}
}
And finally the encoder (the decoder is similar):
public class SomeDataEncoder extends MessageToByteEncoder<SomeData> {
#Override
protected void encode(ChannelHandlerContext ctx, SomeData msg, ByteBuf out) throws Exception {
System.out.println("in encoder, msg = " + msg);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(msg.getName());
oos.writeObject(msg.getIp());
oos.writeInt(msg.getPort());
oos.close();
byte[] serialized = bos.toByteArray();
int size = serialized.length;
ByteBuf encoded = ctx.alloc().buffer(size);
encoded.writeBytes(bos.toByteArray());
out.writeBytes(encoded);
}
}
The client side:
public class Client {
String host = "10.188.36.66";
int port = 5000;
EventLoopGroup workerGroup = new NioEventLoopGroup();
ChannelFuture f;
private Channel ch;
public Client() {
}
public void startClient() throws InterruptedException {
Bootstrap boot = new Bootstrap();
boot.group(workerGroup);
boot.channel(NioSocketChannel.class);
boot.option(ChannelOption.SO_KEEPALIVE, true);
boot.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
// Inbound
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 0));
ch.pipeline().addLast(new SomeDataDecoder());
// Outbound
ch.pipeline().addLast(new LengthFieldPrepender(2));
ch.pipeline().addLast(new SomeDataEncoder());
// Handler
ch.pipeline().addLast(new SomeDataHandler());
}
});
// Start the client
f = boot.connect(host, port).sync();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
System.out.println("connected to server");
ch = f.channel();
}
});
}
public void stopClient() {
workerGroup.shutdownGracefully();
}
private void writeMessage(String input) {
SomeData data = new SomeData("client", "localhost", 3333);
ChannelFuture fut = ch.writeAndFlush(data);
fut.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
System.out.println("send message");
}
});
}
public static void main(String[] args) throws InterruptedException {
Client client = new Client();
client.startClient();
System.out.println("running.\n\n");
final Scanner scanner = new Scanner(System.in);
while (true) {
final String input = scanner.nextLine();
if ("q".equals(input.trim())) {
break;
} else {
client.writeMessage(input);
}
}
scanner.close();
client.stopClient(); //call this at some point to shutdown the client
}
}
and the handler:
public class SomeDataHandler extends SimpleChannelInboundHandler<SomeData> {
private ChannelHandlerContext ctx;
#Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("connected");
this.ctx = ctx;
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, SomeData msg) throws Exception {
System.out.println("got message: " + msg);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.out.println("caught exception: " + cause.getMessage());
ctx.close();
}
}
When I send a message via the console on the server side, I get the output:
running.
duplex channel active
duplex read
idle: ALL_IDLE
idle: ALL_IDLE
send message ok
So it looks as though the message is sent but nothing is received on the client side.
When I do it from the client side I get (on the server console):
in decoder, numBytes in message = 31
duplex channelRead
received: SomeData [name=client, ip=localhost, port=3333]
which is what I expect.
So where's the problem? Is it something to do with using a ChannelDuplexHandler on the server side and a SimpleChannelInboundHandler on the client side? Is there something I need to call to kick the message down the pipeline?
UPDATE
I've added a check for future.isSuccess() in the server sendMessage method and I get
send error: java.lang.UnsupportedOperationException on the console.
(Posted on behalf of the OP).
For anyone who's interested, the problem was that I was trying to send the message on the server channel and not the normal channel. This post pointed me in the right direction.
I dont understand this statement about closing over the actor ref in the callback.
Currently I am using
public void onReceive(Object message) throws Exception {
ActorRef senderActorRef = getSender(); //never close over a future
if (message instanceof String) {
Future<String> f =akka.dispatch.Futures.future(new Callable<String>() {
public String call() {
String value= jedisWrapper.getString("name");
senderActorRef.tell((String) message,ActorRef.noSender());
return "what";
}
}, ex);
f.onSuccess(new OnSuccessExtension(), ex);
}
}
private final class OnSuccessExtension extends OnSuccess {
#Override
public void onSuccess(Object arg0) throws Throwable {
log.info("what");
}
}
Is this the right way to use it?
How can I pass the Sender Actor ref in the OnSuccess method?
Also whats the difference between onSuccess and OnComplete ?
If I want to use onComplete how would I use it?
Answer: Pass the Sender Actor Ref in the constructor. The answer given by another user.
OnSuccess is a specialized form of OnComplete.
OnComplete useage from Akka docs
final ExecutionContext ec = system.dispatcher();
future.onComplete(new OnComplete<String>() {
public void onComplete(Throwable failure, String result) {
if (failure != null) {
//We got a failure, handle it here
} else {
// We got a result, do something with it
}
}
}, ec);
Pass it in the constructor:
public void onReceive(Object message) throws Exception {
final ActorRef senderActorRef = getSender(); //never close over a future
if (message instanceof String) {
Future<String> f = // ...
f.onSuccess(new OnSuccessExtension(senderActorRef), ex);
}
}
private final class OnSuccessExtension extends OnSuccess {
private final ActorRef senderActorRef;
public OnSuccessExtension(ActorRef senderActorRef) {
this.senderActorRef = senderActorRef;
}
#Override
public void onSuccess(Object arg0) throws Throwable {
log.info("what");
// use senderActorRef
}
}
Initially able to make the connection. Simply close the connection client and try to connect again or restart the client. the connection is not established. It creates connection only once.
Can someone help me to improve it. So, it can handle n number client simultaneously.
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new DelimiterBasedFrameDecoder(20000, Delimiters.lineDelimiter()));
// p.addLast(new StringDecoder());
// p.addLast(new StringEncoder());
p.addLast(serverHandler);
}
});
// Start the server.
LOGGER.key("Simulator is opening listen port").low().end();
ChannelFuture f = b.bind(config.getPort()).sync();
LOGGER.key("Simulator started listening at port: " + config.getPort()).low().end();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
LOGGER.key("Shtting down all the thread if anyone is still open.").low().end();
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
Server Handler code is below:
public class SimulatorServerHandler extends SimpleChannelInboundHandler<String> {
private AtomicReference<ChannelHandlerContext> ctxRef = new AtomicReference<ChannelHandlerContext>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private AtomicInteger seqNum = new AtomicInteger(1);
private final Configuration configure;
private ScheduledFuture<?> hbTimerWorker;
private final int stx = 0x02;
private final int etx = 0x03;
private final ILogger LOGGER;
public int enablePublishFunction = 0;
public SimulatorServerHandler(Configuration config) {
this.configure = config;
//LOGGER = LogFactory.INSTANCE.createLogger();
LOGGER = new LogFactory().createLogger("SIM SERVER");
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctxRef.set(ctx);
enablePublishFunction =1;
// System.out.println("Connected!");
LOGGER.low().key("Gateway connected to the Simulator ").end();
startHBTimer();
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
hbTimerWorker.cancel(false);
enablePublishFunction =0;
LOGGER.low().key("Gateway disconnected from the Simulator ").end();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, String request) {
// Generate and write a response.
String response;
boolean close = false;
/* if (request.isEmpty()) {
response = "Please type something.\r\n";
} else if ("bye".equals(request.toLowerCase())) {
response = "Have a good day!\r\n";
close = true;
} else {
response = "Did you say '" + request + "'?\r\n";
}
// We do not need to write a ChannelBuffer here.
// We know the encoder inserted at TelnetPipelineFactory will do the conversion.
ChannelFuture future = ctx.write(response);
// Close the connection after sending 'Have a good day!'
// if the client has sent 'bye'.
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}
*/
System.out.println(request);
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
LOGGER.key("Unknown exception while network communication :"+ cause.getStackTrace()).high().end();
cause.printStackTrace();
ctx.close();
}
Maybe because you use always the very same server handler in your pipeline for all connections (not using new ServerHandler())? Side effects in your implementation could block your handler to be reusable.
I have an application which consists of two parts as server and client.
It works like this :
Client connects to the server and sends a string; server receives the string and returns an ArrayList (by converting string) which contains 10000 elements.
I wrote a class (ClientConnector.java) which simulates many clients use one connection to take those 10000 elements from server.
When I run this two programs, server side is ok. However on the client side, used heap is always increasing ! I tried to release the used objects by "null" but the used memory is still getting larger and larger.
http://s10.postimage.org/egf4ugrd5/mem.png
My Server Side Codes :
Client.java
public class Client {
private static final int PORT = 7571;
ClientHandler handler = new ClientHandler("hey");
IoConnector connector;
boolean available = true;
public synchronized void setAvailable(boolean available) {
this.available = available;
}
public synchronized boolean isAvailable() {
return available;
}
public void starter() throws InterruptedException {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20 * 150000);
t.setDecoderMaxLineLength(20 * 150000);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
connector.setHandler(handler);
ConnectFuture future = connector.connect(new InetSocketAddress("localhost", PORT));
future.awaitUninterruptibly();
if (!future.isConnected()) {
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
});
t.start();
Thread.sleep(300);
}
public void conClose() {
connector.dispose();
}
public ClientHandler getHandler() {
return handler;
}
public void reqInf() {
handler.reqInfo();
}
public static void main(String[] args) {
try {
Client c = new Client();
c.starter();
} catch (InterruptedException ex) {
System.out.println("error");
}
}
}
ClientHandler.java
public class ClientHandler extends IoHandlerAdapter {
long time;
private final String values;
IoSession session;
public ClientHandler(String values) {
this.values = values;
}
#Override
public void sessionOpened(IoSession session) throws InterruptedException {
this.session = session;
}
public ArrayList<String> convert(String str) {
Gson gson = new Gson();
return gson.fromJson(str, ArrayList.class);
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
try {
ArrayList<String> test = convert(message.toString());
System.out.println("TIME : " + (System.currentTimeMillis() - time) + " strList:" + test.size());
message = null;
test = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
System.out.println(cause.toString());
}
#Override
public void sessionClosed(IoSession session) {
System.out.println("Connection Lost");
}
public void reqInfo() {
time = System.currentTimeMillis();
session.write("test");
}
}
My Server Side :
Server.java
public class Server {
private static final int PORT = 7571; //TEST PORT
IoAcceptor acceptor = new NioSocketAcceptor();
public Server() throws IOException {
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20*150000);
t.setDecoderMaxLineLength(20*150000);
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
// acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
Executor executor = new ThreadPoolExecutor(5, 70, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(executor));
acceptor.setHandler(new ServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
//timer();
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("***Mina Server is ready !");
System.out.println("");
System.out.println("");
}
public static void main(String[] args) throws IOException {
Server m = new Server();
}
}
ServerHandler.java
public class ServerHandler extends IoHandlerAdapter {
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
IoSession sessions;
//Communication communication;
public ServerHandler() throws IOException {
loader();
// communication = new Communication(this);
}
#Override
public void sessionOpened(IoSession session) {
// set idle time to 10 seconds
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
System.out.println("Client Connected !!!");
//session.setAttribute("Values: ");
this.sessions = session;
}
public String toGSon(ArrayList<String> list) {
Gson gson = new Gson();
String str = gson.toJson(list);
return str;
}
ArrayList<String> str = new ArrayList<String>();
public void loader() {
for (int i = 0; i < 10000; i++) {
str.add("test" + i);
}
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
long time = System.currentTimeMillis();
session.write(toGSon(str));
System.out.println("TIME : " + (System.currentTimeMillis() - time));
}
#Override
public void sessionIdle(IoSession session, IdleStatus status) {
System.out.println("Socket #" + session.getId() + " is disconnecting... (IDLE)");
session.close();
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
System.out.println("------------>" + cause.toString());
session.close();
}
}
And my Main Class
public class ClientConnector {
public ClientConnector() throws InterruptedException {
Client cl = new Client();
cl.starter();
while (true) {
cl.reqInf();
Thread.sleep(100);
}
}
public static void main(String[] args) throws InterruptedException {
ClientConnector cl = new ClientConnector();
}
}
You must remove below code from client side.
session.getConfig().setUseReadOperation(true);
Above code will cause memory leak.
One of our developers found an issue in Mina with the way clean up was being done and a patch was applied to version 2.0.8. Since as of today this is "snapshot" you have to grab it from git and build it yourself. Here is the command to get it from git:
git checkout 2.0
Repository uri:
git clone http://git-wip-us.apache.org/repos/asf/mina.git
This code is not enough to reach to a pin pointed answer.
Heap size continuous increase and no effect of GC --> Signs of memory leak.
Probably you should Profile your application and use some OQL Tools to find out which class is using char[], which here is the culprit looking at heap dump in your case