I hope to realize the following communication among three parties:
The communication process is:
(1) A sends M1 to B
(2) B, after receiving M1, forwards to C
(3) C, after receiving M1, responds with M2
(4) B, after receiving M2, forward M2 to A
(5) Finally A output M2
I have realized all the code using Netty, but currently the problem is:
after B receiving M2 from C, I tried to put M2 to the communication channel between A and B, hoping that A can directly receive it, but it seems it fails. Thanks in advance if anyone can help, and the following is a basic implementation of my code:
A.java sends M1 to B, and AHandler.java listens on what sent by B:
// A.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class A {
public static void main(String[] args) {
// loop group
EventLoopGroup loopGroup = new NioEventLoopGroup();
// create bootstrap
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(loopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new AHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost", 6002).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
loopGroup.shutdownGracefully();
}
}
}
// AHandler.java
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.util.CharsetUtil;
public class AHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String M1 = "M1";
ctx.writeAndFlush(Unpooled.copiedBuffer(M1, CharsetUtil.UTF_8));
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// !!! Hope to receive what B forwards from C, namely M2, but cannot receive it
ByteBuf buf = (ByteBuf) msg;
System.out.println("B responds receipt: " + buf.toString(CharsetUtil.UTF_8));
}
}
B listens on port 6002, and after receiving M1 from A, forwards to C by creating a new channel between B and C:
// B.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class B {
public static void main(String[] args) {
// create thread pool
// create Boss group : receiving client connection
EventLoopGroup bossGroup = new NioEventLoopGroup();
// create work group: network read and communication
EventLoopGroup workGroup = new NioEventLoopGroup();
// create start class
ServerBootstrap bootstrap = new ServerBootstrap();
try {
bootstrap.group(bossGroup, workGroup) // set thread group
.channel(NioServerSocketChannel.class) //set channel
.option(ChannelOption.SO_BACKLOG, 1024) // set the number of thread connections
//.option(ChannelOption.SO_KEEPALIVE, true) // keep connection
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new BHandler());
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
System.out.println("----- B is online -----");
ChannelFuture channelFuture = bootstrap.bind(6002).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
// BHandler.java (as the server end between A and B)
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.GlobalEventExecutor;
public class BHandler extends ChannelInboundHandlerAdapter {
public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
public static Channel Channel_AB = null;
public void BForwardM1() {
EventLoopGroup loopGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.group(loopGroup)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new BCHandler());
}
});
ChannelFuture future = bootstrap.connect("localhost", 6003).sync();
future.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
loopGroup.shutdownGracefully();
}
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Add channel_AB to channel group
Channel channel_AB = ctx.channel();
Channel_AB = channel_AB;
channelGroup.add(channel_AB);
System.out.println("Received from A: " + channel_AB.remoteAddress() + ", channel ID: " + channel_AB.id());
ByteBuf buf = (ByteBuf) msg;
String M1_From_A = buf.toString(CharsetUtil.UTF_8);
System.out.println("M1_From_A: " + M1_From_A);
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// B forwards M1 to C
BForwardM1();
}
}
// BCHandler.java (as the client end of between B and C)
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.util.CharsetUtil;
public class BCHandler extends ChannelInboundHandlerAdapter{
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
String M1 = "M1";
// B forwards M1 to C
ctx.writeAndFlush(Unpooled.copiedBuffer(M1, CharsetUtil.UTF_8));
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
// C responds with M2
String M2 = buf.toString(CharsetUtil.UTF_8);
System.out.println("Receive C's respond: " + M2);
// !!! Trying to put M2 to AB's channel
BHandler.channelGroup.forEach(ch -> {
if (ch != null) {
ch.writeAndFlush(Unpooled.copiedBuffer(M2, CharsetUtil.UTF_8));
} else {
System.out.println("No available channel");
}
});
}
}
C listens on the port 6003, and responds B with message M2:
// C.java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class C {
public static void main(String[] args) {
// create Boss group : receiving client connection
EventLoopGroup bossGroup = new NioEventLoopGroup();
// create work group: network read and communication
EventLoopGroup workGroup = new NioEventLoopGroup();
// create start class
ServerBootstrap bootstrap = new ServerBootstrap();
try {
bootstrap.group(bossGroup, workGroup) // set thread group
.channel(NioServerSocketChannel.class) //set channel
.option(ChannelOption.SO_BACKLOG, 1024) // set the number of thread connections
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new CHandler());
}
});
System.out.println("----- C is online -----");
ChannelFuture channelFuture = bootstrap.bind(6003).sync();
channelFuture.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}
}
// CHandler.java
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
public class CHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buf = (ByteBuf) msg;
System.out.println("Receive from B: " + buf.toString(CharsetUtil.UTF_8));
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
// C responds with M2
ctx.writeAndFlush(Unpooled.copiedBuffer("M2", CharsetUtil.UTF_8));
}
}
My idea is to pass the AB channel context to the BCHandler.java, which receives the response from C, and then uses the AB channel to send back to A, but it seems that A cannot receive the M2 at the end. Thanks a lot if you can provide help!
Essentially what needs to be realized is a Proxy Server using Netty, so this example can solve the problem and it works for me.
Related
I am working on my online file storage and today I have encountered some issues with my Netty TCP file tranfer. So the problem is that only 8192 bytes of data is actually written in the file on the client-side.
I want to know what the problem is, and how I can fix it.
I have seen ALL of the other (5) stackoverflow questions.
Here is my server bootstrap:
package com.martin.main;
import com.martin.file.*;
import com.martin.handler.*;
import com.martin.utils.*;
import io.netty.bootstrap.*;
import io.netty.channel.*;
import io.netty.channel.nio.*;
import io.netty.channel.socket.*;
import io.netty.channel.socket.nio.*;
import io.netty.handler.codec.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.*;
public class Server {
public static void main(String[] args) {
new Server().setup(4783);
}
public ChannelFuture setup(int port) {
ChannelFuture future = null;
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
final ServerBootstrap bootstrap;
try {
bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//pipeline.addLast("framer", new LengthFieldBasedFrameDecoder());
pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
pipeline.addLast(new LengthFieldPrepender(4));
pipeline.addLast("login", new LoginServerHandler()); //the problem is not in that handler
}
});
future = bootstrap.bind(new InetSocketAddress(port)).sync().channel().closeFuture().sync();
}catch(InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
return future;
}
}
My server-handler:
public class ServerHandler extends ByteToMessageDecoder {
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
#Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
byte msgType = byteBuf.readByte();
if(FILEPACKETINFO == msgType) {
//The problem is probaly here
System.out.println("inide file req.");
int id = byteBuf.readInt();
for(OnlineFile onlineFile : OnlineFile.getOnlineFiles()) {
if(onlineFile.getId() == id) {
System.out.println("file request id: " + id + " actual id: " + onlineFile.getId());
ByteBuf buf = Unpooled.buffer();
buf.writeByte(FILEPACKETINFO);
String fileName = onlineFile.getName();
File file = onlineFile.getActualFile();
buf.writeLong(file.length());
buf.writeInt(fileName.length());
buf.writeCharSequence(fileName, CharsetUtil.US_ASCII);
ctx.writeAndFlush(buf);
if(!(file.length() <= 0)) {
ctx.writeAndFlush(new ChunkedFile(file)).addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
System.out.println("written successfully!");
if (channelFuture.cause() != null) channelFuture.cause().printStackTrace();
}
});
} else {
System.out.println("length 0: " + " (" + file.length() +")");
}
}
}
} else if(REQUESTVISUALFILES == msgType) {
createAndSend(ctx); //send VISUAL files, problem not there
} else if(REQUESTFOLDERFILESBYID == msgType) {
int id = byteBuf.readInt();
createAndSend(ctx, id); //send VISUAL files by id, problem not there
}
}
My client bootstrap:
public static ChannelFuture setup(String host, int port) {
ChannelFuture channelFuture = null;
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group);
bootstrap.channel(NioSocketChannel.class);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
pipeline.addLast("framer", new LengthFieldBasedFrameDecoder(64*1024, 0, 4, 0, 4));
pipeline.addLast(lfp);
pipeline.addLast("login", new LoginHandler()); //the problem is not in that handler either
}
});
channelFuture = bootstrap.connect(new InetSocketAddress(host, port)).sync();
System.out.println("the setup came to an end!");
LoginForm.createAndShowGUI("Login");
mainChannel = channelFuture.channel();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
return channelFuture;
}
}
My client handler:
package com.martin.handler;
import io.netty.buffer.*;
import io.netty.channel.*;
import io.netty.util.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
public class FileChunkHandler extends SimpleChannelInboundHandler<ByteBuf> {
public static String currentFileName = "Test.txt";
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.pipeline().remove(this);
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
//the problem is probably here
System.out.println("inside FileChunkHandler current file: " + currentFileName);
ByteBuffer buffer = byteBuf.nioBuffer();
System.out.println(buffer.capacity() + " buffer" + " bytebuf: " + byteBuf.readableBytes());
File file = triggerFileCreation();
// FileOutputStream fos = new FileOutputStream("C:\\Users\\marti\\storage\\" + currentFileName);
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
FileChannel channel = randomAccessFile.getChannel();
while(buffer.hasRemaining()) {
channel.position(file.length());
channel.write(buffer);
System.out.println("chunk has just been written");
}
channel.close();
randomAccessFile.close();
//!!!--->IMPORTANT<-----!!!
ctx.pipeline().remove(this);
}
public static File triggerFileCreation() {
File file = new File(System.getProperty("user.home") + "/storage/" + currentFileName);
if(!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
}
EDIT
The problem was that I removed the handler too quickly, then other packets got handled in other handlers/were dropped from the pipeline.
The problem is indeed most likely to be in your FileChunkHandler.
You only read a single buffer (likely containing 8192 bytes - 8kB), and then remove the handler. The remaining chunks either get "handled" by some other handler in the pipeline, or reach the end of the pipeline and get dropped. As mentioned in Discord, you need to keep track of how many bytes you are expecting, subtract the number received, and only when that number reaches 0, should you remove the handler.
I'm opening a simple tcp server, but netty client can't connect.
if necessary
(netty client) <-----> (netty server) it works
(simple tcp client) <-----> (simple tcp server) it works
but
(netty client) <----> (simple tcp server) doesn't work
can you help me
public class TCPServer extends Thread {
private ServerSocket serverSocket;
public TCPServer(int port) throws IOException {
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run() {
while(true) {
try {
System.out.println("Waiting for client on port " +
serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("Just connected to " + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress()
+ "\nGoodbye!");
// server.close();
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
// break;
} catch (IOException e) {
e.printStackTrace();
// break;
}
}
}
public static void main(String [] args) {
int port = 14115;
try {
Thread t = new TCPServer(port);
t.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
---Client----
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
public final class Client {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "14115"));
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new StringDecoder());
p.addLast(new StringDecoder());
p.addLast(new ClientHandler());
}
});
b.option(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.connect(HOST, PORT).sync();
} finally {
group.shutdownGracefully();
}
}
}
---Client Handler---
public class ClientHandler extends ChannelInboundHandlerAdapter {
public ClientHandler() {
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("Channel Active");
try {
ctx.writeAndFlush("Hello Server");
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println("client received: " + msg);
ctx.writeAndFlush(msg);
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
I need to have a client/server communication in netty for one of my project purpose. So I just started with a handsOn to improve from that.I am learning netty and I am a beginner in that.
I have tried a simple client server chatting with netty.
The client and server is getting initialized and I could see the server is able to get the Client pipeline for connection establishment, but when the client sends the message, it is not getting inside the messageReceived part of the ServerAdapterHandler. Below are my source codes,
CLIENT:
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
public class ContainerClient {
String server;
int port;
int containerPort;
public ContainerClient(String server, int port, int containerPort) {
this.server = server;
this.port = port;
this.containerPort = containerPort;
}
public static void main(String[] args) {
String server = "localhost";
int port = 5252;
int containerPort = 8094;
new ContainerClient(server, port, containerPort).start();
}
public void start() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap().group(group)
.channel(NioSocketChannel.class)
.handler(new ClientAdapterInitializer());
Channel channel = bootstrap.connect(server, port).sync().channel();
channel.write("Hi\n");
channel.write("Hi\n");
channel.write("Hi\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
CLIENT CHANNEL INITIALIZER:
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class ClientAdapterInitializer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ClientAdapterHandler());
}
}
CLIENT MESSAGE HANDLER:
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
public class ClientAdapterHandler extends
ChannelInboundMessageHandlerAdapter<String> {
#Override
public void messageReceived(ChannelHandlerContext context, String message)
throws Exception {
System.out.println(message);
if (message.equals("quit"))
throw new ServerEndedException("Server is closed");
}
#Override
public void channelRead(ChannelHandlerContext arg0, Object arg1)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public void channelReadComplete(ChannelHandlerContext arg0)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public void channelWritabilityChanged(ChannelHandlerContext arg0)
throws Exception {
// TODO Auto-generated method stub
}
}
SERVER:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class ContainerServer {
int port;
public static void main(String[] args) {
new ContainerServer().start();
}
public void start() {
port = 5252;
EventLoopGroup producer = new NioEventLoopGroup();
EventLoopGroup consumer = new NioEventLoopGroup();
try {
ServerBootstrap bootstrap = new ServerBootstrap()
.group(producer, consumer)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerAdapterInitializer());
System.out.println("Server started");
bootstrap.bind(port).sync().channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
producer.shutdownGracefully();
consumer.shutdownGracefully();
}
}
}
SERVER CHANNEL INITIALIZER:
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class ServerAdapterInitializer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new ServerAdapterHandler());
}
}
SERVER MESSAGE HANDLER:
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundMessageHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
public class ServerAdapterHandler extends
ChannelInboundMessageHandlerAdapter<String> {
private static final ChannelGroup channels = new DefaultChannelGroup(
"containers", GlobalEventExecutor.INSTANCE);
#Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("[START] New Container has been initialzed");
channels.add(ctx.channel());
super.handlerAdded(ctx);
}
#Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("[END] A Container has been removed");
channels.remove(ctx.channel());
super.handlerRemoved(ctx);
}
#Override
public void messageReceived(ChannelHandlerContext ctx, String arg1)
throws Exception {
Channel currentChannel = ctx.channel();
System.out.println("[INFO] - " + currentChannel.remoteAddress() + " - "
+ arg1);
currentChannel.write("[Server] - Success");
}
#Override
public boolean beginMessageReceived(ChannelHandlerContext ctx)
throws Exception {
System.out.println("Message received");
return super.beginMessageReceived(ctx);
}
#Override
public void channelRead(ChannelHandlerContext arg0, Object arg1)
throws Exception {
System.out.println("channelRead");
}
#Override
public void channelReadComplete(ChannelHandlerContext arg0)
throws Exception {
// TODO Auto-generated method stub
System.out.println("channelReadComplete");
}
#Override
public void channelWritabilityChanged(ChannelHandlerContext arg0)
throws Exception {
// TODO Auto-generated method stub
System.out.println("channelWritabilityChanged");
}
}
Below is the output I am getting in server and nothing in client:
Server started
[START] New Container has been initialzed
channelReadComplete
[END] A Container has been removed
But The expected should be,
Server started
[START] New Container has been initialzed
channelReadComplete
[INFO] - localhost - Hi
[INFO] - localhost - Hi
[INFO] - localhost - Hi
[END] A Container has been removed
And I should get response in client as,
[Server] - Success
[Server] - Success
[Server] - Success
I tried with line Delimter in framer also, but same results.
Someone could you please help on this?
Thanks in advance!!.
It works for me with the following change to the start method in your ContainerClient. Just add a channel.flush().
public void start() {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap().group(group).channel(NioSocketChannel.class).handler(new ClientAdapterInitializer());
Channel channel = bootstrap.connect(server, port).sync().channel();
channel.write("Hi\n");
channel.write("Hi\n");
channel.write("Hi\n");
channel.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
The ChannelInboundMessageHandlerAdapter does not exist anymore in newer version of 4.0. I used a SimpleChannelInboundHandler.
public class ServerAdapterHandler extends SimpleChannelInboundHandler<String> {
#Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
Channel currentChannel = ctx.channel();
System.out.println("[INFO] - " + currentChannel.remoteAddress() + " - " + msg);
currentChannel.write("[Server] - Success");
}
}
We are trying to create a system using Javas RMI. The problem is that a maintained list on the client cannot be accessed from the server using Java RMI. It seems that the RMI connection is handling a copy of the initialized list.
Below is a minimal example using an integer that the client increments every second until it equals 10. The server receives 0 all the time though.
Anyone have any idea what we are doing wrong?
Just run server and the client as a java application.
ServerDefaultImpl.java
package rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class ServerDefaultImpl implements EIServerRemote, Runnable {
ClientRemote client;
private boolean running = true;
public ServerDefaultImpl() {
try {
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
ServerDefaultImpl server = this;
EIServerRemote stub = (EIServerRemote) UnicastRemoteObject.exportObject(server, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("test", stub);
} catch (RemoteException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ServerDefaultImpl();
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
if (null != client) { //Client not connected yet.
int test = client.test();
System.out.println(test);
running = test <= 10;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void attachClientListener(ClientRemote client) throws RemoteException {
this.client = client;
}
}
EIServerRemote.java
package rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface EIServerRemote extends Remote {
void attachClientListener(ClientRemote client) throws RemoteException;
}
ClientRemote.java
package rmi;
import java.io.Serializable;
import java.rmi.Remote;
public interface ClientRemote extends Remote,Serializable {
int test();
}
ClientDefaultImpl.java
package rmi;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class ClientDefaultImpl implements Runnable,
ClientRemote {
private static final long serialVersionUID = 4846141863099303590L;
protected EIServerRemote server = null;
public int test;
public boolean running = true;
public ClientDefaultImpl(String serverName) {
test = 0;
try {
connect(serverName);
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ClientDefaultImpl("test");
}
public void connect(String serverName) throws RemoteException,
NotBoundException {
Registry registry = LocateRegistry.getRegistry();
EIServerRemote s = (EIServerRemote) registry.lookup(serverName);
server = s;
s.attachClientListener((ClientRemote) this);
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
System.out.println(test++);
running = test <= 10;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public int test() {
return test;
}
}
It seems that the RMI connection is handling a copy of the initialized list.
That's correct. The list isn't a remote object, so it is passed and returned via serialization.
I am writing a simple routing application. The idea is that I have servers or source nodes that receive transient clients connections that last for a period of x time. The messages received are decoded and then sent to a corresponding sink node or client that is/are already open depending on the details of the message. The Router class registers all channels and attemps to save them in maps so that it can filter and worj out the destination of the message. Once I get the destination, I should then be able to pick the actual sink node (could be of transient of persistent nature depending on the configurations) and send data to that channel wait for a response and then send it back to the originator. I'd like to know first if my implementation using netty is in the right direction ? and how can I pass a message received from any of the servers and send it to any of the clients and respond back to the originating source node ?
Below is my source code : It will / should give you an idea of what I am up to :Kindly use code examples in your explanation .
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
/*
* #author Kimathi
*/
public class Service {
private Nodes nodes;
public void start(){
nodes = new Nodes();
nodes.addSourceNodes(new SourceNodes()).
addSinkNodes(new SinkNodes()).
addConfigurations(new Configurations()).
boot();
}
public void stop(){
nodes.stop();
}
public static void main(String [] args){
new Service().start();
}
}
class Nodes {
private SourceNodes sourcenodes;
private SinkNodes sinknodes ;
private Configurations configurations;
public Nodes addConfigurations(Configurations configurations){
this.configurations = configurations;
return this;
}
public Nodes addSourceNodes(SourceNodes sourcenodes){
this.sourcenodes = sourcenodes;
return this;
}
public Nodes addSinkNodes(SinkNodes sinknodes){
this.sinknodes = sinknodes;
return this;
}
public void boot(){
Router router = new Router(configurations);
sourcenodes.addPort(8000).
addPort(8001).
addPort(8002);
sourcenodes.addRouter(router);
sourcenodes.boot() ;
sinknodes.addRemoteAddress("127.0.0.1", 6000).
addRemoteAddress("127.0.0.1", 6001).
addRemoteAddress("127.0.0.1", 6002);
sinknodes.addRouter(router);
sinknodes.boot();
}
public void stop(){
sourcenodes.stop();
sinknodes.stop();
}
}
final class SourceNodes implements Bootable , Routable {
private List <Integer> ports = new ArrayList();
private ServerBootstrap serverbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SourceNodes addPort(int port){
this.ports.add(port);
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.serverbootstrap.setOption("child.tcpNoDelay", true);
this.serverbootstrap.setOption("child.keepAlive", true);
this.serverbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SourceHandler(router));
}
});
for(int port:this.ports){
this.serverbootstrap.bind(new InetSocketAddress(port));
}
}
#Override
public void stop(){
this.serverbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.serverbootstrap = new ServerBootstrap(factory);
}
}
final class SinkNodes implements Bootable , Routable {
private List<SinkAddress> addresses= new ArrayList();
private ClientBootstrap clientbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SinkNodes addRemoteAddress(String hostAddress,int port){
this.addresses.add(new SinkAddress(hostAddress,port));
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.clientbootstrap.setOption("tcpNoDelay", true);
this.clientbootstrap.setOption("keepAlive", true);
this.clientbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SinkHandler(router));
}
});
for(SinkAddress address:this.addresses){
this.clientbootstrap.connect(new InetSocketAddress(address.hostAddress(),address.port()));
}
}
#Override
public void stop(){
this.clientbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.clientbootstrap = new ClientBootstrap(factory);
}
private class SinkAddress {
private final String hostAddress;
private final int port;
public SinkAddress(String hostAddress, int port) {
this.hostAddress = hostAddress;
this.port = port;
}
public String hostAddress() { return this.hostAddress; }
public int port() { return this.port; }
}
}
class SourceHandler extends SimpleChannelHandler {
private Router router;
public SourceHandler(Router router){
this.router = router;
}
#Override
public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
System.out.println("child is opened");
}
#Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("child is closed");
}
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Server is opened");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
class SinkHandler extends SimpleChannelHandler {
private Router router;
public SinkHandler(Router router){
this.router = router;
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Channel is connected");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
final class Router {
private Configurations configurations;
private Map sourcenodes = new HashMap();
private Map Sinknodes = new HashMap();
public Router(){}
public Router(Configurations configurations){
this.configurations = configurations;
}
public synchronized boolean submitSource(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
public synchronized boolean submitSink(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
}
final class Configurations {
public Configurations(){}
}
interface Bootable {
public abstract void boot();
public abstract void stop();
}
interface Routable {
public abstract void addRouter(Router router);
}
The idea seems reasonable.
The source channel handler can just write to the corresponding sink channel, using Channel#write(...), and vice versa on the reply.
Of course, you also need a way to correlate the source channel with the reply, and how that is best done depends an the nature of the protocol. The best alternative, if possible, is to somehow encode the source channel id in the message to the sink channel (and also in the reply, of course).
If that is not possible, you will somehow have to maintain the correlation. A FIFO queue per sink channel may be appropriate if the replies are guaranteed to pair up with the sent requests.