Netty channel write not reaching handlers - java

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.

Related

Client not seing the buffer sent by a TCP server in netty

I have developed in Netty a TCP Server and a TCP client. What I am trying to do is:
I create the TCP Client and listen to the port
I create the server
I listen to the input stream and sends a content to the port
I used the solution proposed by the following StackOverflow answer here for the code.
Everything seems to be OK, but the Client does not receive anything. What did I done wrong? To be complete at the beginning my TCP Client was coded in Python, I created a Java client because I did not understand why I did not receive anything, but I have the same problem when my Client is in java (see my complete code below).
The complete code is here:
public class TestTCPNetty {
private ChannelGroup allChannels = null;
private final int serverPort = 8080;
public static void main(String[] args) {
TestTCPNetty netty = new TestTCPNetty();
netty.start();
}
private void setupClient() {
InetSocketAddress addr = new InetSocketAddress(serverPort);
NioEventLoopGroup clientworkerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
TcpClientHandler handler = new TcpClientHandler();
bootstrap.group(clientworkerGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.option(ChannelOption.SO_RCVBUF, 500);
bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(500));
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 500);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(handler);
}
});
bootstrap.remoteAddress(addr);
bootstrap.connect();
}
private void setupServer() {
allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
try {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("MyMessageHandler", new MyMessageHandler());
ch.pipeline().addLast("grouper", new GlobalSendHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(serverPort).sync();
Channel ch = f.channel();
ByteBufAllocator alloc = ch.alloc();
System.out.println("Server: Running!");
// Read commands from the stdin.
ChannelGroupFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String line = in.readLine();
if (line == null) {
break;
}
ByteBuf getOut = alloc.buffer(64);
getOut.writeBytes(line.getBytes());
// Sends the received line to the server.
lastWriteFuture = allChannels.writeAndFlush(getOut);
lastWriteFuture.addListener(new ChannelGroupFutureListener() {
#Override
public void operationComplete(ChannelGroupFuture cf) throws Exception {
if (cf.isSuccess()) {
System.out.println("CFListener: SUCCESS! YEAH! HELL! YEAH!");
} else {
System.out.println("CFListener: failure! FAILure! FAILURE!");
System.out.println(cf.cause());
}
}
});
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();
} catch (Exception e) {
}
}
public void start() {
setupClient();
setupServer();
}
public class GlobalSendHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
allChannels.add(ctx.channel());
try {
super.channelActive(ctx);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public class MyMessageHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
}
}
public class TcpClientHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
CharSequence sequence = buf.readCharSequence(buf.readableBytes(), Charset.forName("UTF-8"));
String str = sequence.toString().trim();
System.err.println(str);
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
}
}
I took into account the comment from Norman Maurer. In the new code I am performing the Client connection and runtime in another Thread:
public class TestTCPNetty {
private ChannelGroup allChannels = null;
private final int serverPort = 8080;
public static void main(String[] args) {
TestTCPNetty netty = new TestTCPNetty();
netty.start();
}
private void setupClient() {
InetSocketAddress addr = new InetSocketAddress(serverPort);
NioEventLoopGroup clientworkerGroup = new NioEventLoopGroup();
Bootstrap bootstrap = new Bootstrap();
TcpClientHandler handler = new TcpClientHandler();
bootstrap.group(clientworkerGroup);
bootstrap.channel(NioSocketChannel.class);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
bootstrap.option(ChannelOption.SO_RCVBUF, 500);
bootstrap.option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(500));
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 500);
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(handler);
}
});
bootstrap.remoteAddress(addr);
try {
ChannelFuture f = bootstrap.connect().sync();
System.out.println("Future is failed ? " + f.isSuccess());
} catch (Exception e) {
e.printStackTrace();
}
}
private void setupServer() {
allChannels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
try {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("MyMessageHandler", new MyMessageHandler());
ch.pipeline().addLast("grouper", new GlobalSendHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
ChannelFuture f = b.bind(serverPort).sync();
Channel ch = f.channel();
ByteBufAllocator alloc = ch.alloc();
System.out.println("Server: Running!");
// Read commands from the stdin.
ChannelGroupFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String line = in.readLine();
if (line == null) {
break;
}
ByteBuf getOut = alloc.buffer(64);
getOut.writeBytes(line.getBytes());
// Sends the received line to the server.
lastWriteFuture = allChannels.writeAndFlush(getOut);
lastWriteFuture.addListener(new ChannelGroupFutureListener() {
#Override
public void operationComplete(ChannelGroupFuture cf) throws Exception {
if (cf.isSuccess()) {
System.out.println("CFListener: SUCCESS! YEAH! HELL! YEAH!");
} else {
System.out.println("CFListener: failure! FAILure! FAILURE!");
System.out.println(cf.cause());
}
}
});
}
// Wait until all messages are flushed before closing the channel.
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
// Wait until the server socket is closed.
// In this example, this does not happen, but you can do that to gracefully
// shut down your server.
f.channel().closeFuture().sync();
} catch (Exception e) {
}
}
public void start() {
Thread t1 = new Thread(new Runnable() {
public void run() {
setupClient();
}
});
t1.start();
setupServer();
}
public class GlobalSendHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
allChannels.add(ctx.channel());
try {
super.channelActive(ctx);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public class MyMessageHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
}
}
public class TcpClientHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf buf = (ByteBuf) msg;
CharSequence sequence = buf.readCharSequence(buf.readableBytes(), Charset.forName("UTF-8"));
String str = sequence.toString().trim();
System.err.println(str);
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
ctx.close();
}
}
}
Now the Client connection work (I receive the message "Server: Running!" then "Future is failed ? true"), but the Client still receives nothing.

java io netty how to get next packet from a client

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) {
}
}
}

Getting io.netty.handler.codec.TooLongFrameException at Server side when receiving message from Order Management System in Netty

I implemented a basic Server program using Netty. OMS sends group of message strings to the server and the server accepts and displays it to the terminal.I can't receive the message.It is showing the below Exceptions instead.I think the decoded size has exceeded the maximum limit.
If this is correct how to decode any sized string?? That is,is there anyway that dynamically takes the length of the string and receives the exact string from the Buffer?
My Client Code:
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception{
EventLoopGroup group = new NioEventLoopGroup();
try{
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>(){
#Override
public void initChannel(SocketChannel ch) throws Exception{
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(204800, 0, 4, 0, 4))
.addLast(new LengthFieldPrepender(4))
.addLast(new EchoClientHandler());
}
});
ChannelFuture future = b.connect().sync();
future.channel().closeFuture().sync();
}
finally {
group.shutdownGracefully().sync();
}
}
public static void main (String [] args) throws Exception {
new EchoClient("127.0.0.1", 11235).start();
}
}
My ClientHandler :
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf>{
#Override
public void channelActive(ChannelHandlerContext ctx){
System.out.println("Connected");
int i=0;
while(i<100){
ctx.writeAndFlush(Unpooled.copiedBuffer("8=FIX.4.29=0007935=A49=TTDS68AO56=RaviEx34=152=20170427-14:05:04.572108=60141=Y98=010=242\n",
CharsetUtil.UTF_8));
i++;
}
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
cause.printStackTrace();
ctx.close();
}
}
My Server:
public class EchoServer{
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
System.out.println("New client connected: " + ch.localAddress());
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(204800, 0, 4, 0, 4))
.addLast(new LengthFieldPrepender(4))
.addLast(new EchoServerHandler());
}
});
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
}
finally {
group.shutdownGracefully().sync();
}
}
public static void main (String [] args) throws Exception {
new EchoServer(11235).start();
}
}
MyEchoSeverHandler:
public class EchoServerHandler extends ChannelInboundHandlerAdapter{
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println(in.toString(CharsetUtil.UTF_8));
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

Netty send message to Server without for loop

I was using the following code to send messages from the Client to the Server:
Client class:
public class Client {
String host = "localhost";
int port = 14930;
private final ClientHandler clientHandler = new ClientHandler();
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws Exception {
try {
workerGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(clientHandler);
}
}
);
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
}
finally {
workerGroup.shutdownGracefully();
}
}
public void writeMessage(String msg) {
clientHandler.sendMessage(msg);
}
}
Handler class:
public class ClientHandler extends SimpleChannelInboundHandler<String> {
ChannelHandlerContext ctx;
public void sendMessage(String msgToSend) {
ctx.writeAndFlush(Unpooled.copiedBuffer(msgToSend, CharsetUtil.UTF_8));
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
#Override
protected void channelRead0(ChannelHandlerContext arg0, String msg) throws Exception {
}
void channelInactive(ChannelHandlerContext ctx) throws Exception {
}
}
I am creating the Client like this:
Client client;
client = new Client(ipAddress, serverPort);
client.run();
client.writeMessage("random_text");
The Server:
public final class ChatServer {
public ChatServer(int PORT) throws Exception {
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChatServerInitializer());
b.bind(PORT).sync().channel().closeFuture().sync();
}
finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
ServerHandler:
public class ChatServerHandler extends SimpleChannelInboundHandler<String> {
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
channels.add(ctx.channel());
}
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = ctx.channel();
channels.remove(ctx.channel());
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
println(msg);
}
}
Method to send Message from Server to Client:
public void sendMessage(String message) {
if (message != "" && message != null) {
for (Channel c : channels) {
c.writeAndFlush(message + "\r\n");
}
}
}
The problem is that the Server does not get any Messages. I tried some debug steps, the Server adds the Client to its channels, and channelActive gets executed successfully on the Client side.
Instead of polling the variable the whole time you should try to transfer the communication to the handler (either your ChatClientInitializer or an extra handler that you add last). Give this handler a method that you call when a new message was entered. The handler then writes to the channel.
Maybe this example helps:
public class Client implements Runnable {
String host = "localhost";
int port = 9128;
private final ClientHandler clientHandler = new ClientHandler();
private boolean isRunning = false;
private ExecutorService executor = null;
public static void main(String[] args) {
Client client = new Client();
client.startClient();
client.writeMessage("random_text");
//client.stopClient(); //call this at some point to shutdown the client
}
public synchronized void startClient() {
if (!isRunning) {
executor = Executors.newFixedThreadPool(1);
executor.execute(this);
isRunning = true;
}
}
public synchronized boolean stopClient() {
boolean bReturn = true;
if (isRunning) {
if (executor != null) {
executor.shutdown();
try {
executor.shutdownNow();
if (executor.awaitTermination(calcTime(10, 0.66667), TimeUnit.SECONDS)) {
if (!executor.awaitTermination(calcTime(10, 0.33334), TimeUnit.SECONDS)) {
bReturn = false;
}
}
} catch (InterruptedException ie) {
executor.shutdownNow();
Thread.currentThread().interrupt();
} finally {
executor = null;
}
}
isRunning = false;
}
return bReturn;
}
private long calcTime(int nTime, double dValue) {
return (long) ((double) nTime * dValue);
}
#Override
public void run() {
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
pipeline.addLast(clientHandler);
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} catch (InterruptedException ex) {
// do nothing
} finally {
workerGroup.shutdownGracefully();
}
}
public void writeMessage(String msg) {
clientHandler.sendMessage(msg);
}
}
A very basic ClientHandler:
public class ClientHandler extends SimpleChannelInboundHandler<String> {
ChannelHandlerContext ctx;
public void sendMessage(String msgToSend) {
if (ctx != null) {
ChannelFuture cf = ctx.write(Unpooled.copiedBuffer(msgToSend, CharsetUtil.UTF_8));
ctx.flush();
if (!cf.isSuccess()) {
System.out.println("Send failed: " + cf.cause());
}
} else {
//ctx not initialized yet. you were too fast. do something here
}
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
#Override
protected void channelRead0(ChannelHandlerContext arg0, String msg) throws Exception {
}
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
}
}

A binary chat using netty

I'm trying to modify the securechat example of netty to send bytes (byte array) instead of a string.But I'm unable to send any bytes to the server. what am I doing wrong? It works perfectly if an ObjectDecoder/Encoder is used, but I need raw bytes to be send through the wire.
If instead if a byte[], a ByteBuffer would also suffice, as long as The traffic consists of only those bytes within the buffer.
Can anyone please help?
Client.java
public class Client {
private final String host;
private final int port;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ClientInitializer());
Channel ch = b.connect(host, port).sync().channel();
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (;;) {
String line = in.readLine();
if (line == null) {
break;
}
lastWriteFuture = ch.write(new byte[]{1,2,3,4,5,6,7,8});
}
if (lastWriteFuture != null) {
lastWriteFuture.sync();
}
} finally {
group.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
new Client("localhost",6666).run();
}
}
ClientHandler
public class ClientHandler extends SimpleChannelInboundHandler<Byte[]> {
private static final Logger logger = Logger.getLogger(
ClientHandler.class.getName());
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close();
}
#Override
protected void channelRead0(ChannelHandlerContext chc, Byte[] i) throws Exception {
System.out.println(i[3]);
}
}
ClientInitializer
public class ClientInitializer extends ChannelInitializer<SocketChannel> {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder",
new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
pipeline.addLast("bytesDecoder",
new ByteArrayDecoder());
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("bytesEncoder", new ByteArrayEncoder());
pipeline.addLast("handler", new ClientHandler());
}
}
Server
public class Server {
private final int port;
public Server(int port) {
this.port = port;
}
public void run() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerInitializer());
b.bind(port).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 6666;
}
new Server(port).run();
}
}
ServerHandler
public class ServerHandler extends SimpleChannelInboundHandler<Byte[]> {
private static final Logger logger = Logger.getLogger(
ServerHandler.class.getName());
static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
#Override
public void channelActive(final ChannelHandlerContext ctx) throws Exception {
channels.add(ctx.channel());
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.", cause);
ctx.close();
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, Byte[] i) throws Exception {
for (Channel c: channels) {
if (c != ctx.channel()) {
c.writeAndFlush(i);
}
}
}
}
ServerInitializer
public class ServerInitializer extends ChannelInitializer<SocketChannel> {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("frameDecoder",
new LengthFieldBasedFrameDecoder(1048576, 0, 4, 0, 4));
pipeline.addLast("bytesDecoder",
new ByteArrayDecoder());
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
pipeline.addLast("bytesEncoder", new ByteArrayEncoder());
pipeline.addLast("handler", new ServerHandler());
}
}
You forgot to call channel.flush() in your client after channel.write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }). Because it was never flushed, the server will never receive it. Alternatively, you can use writeAndFlush() which is a shortcut of write(...) and flush().
Just found this example need change to byte[], otherwise it will not be called.
public class ServerHandler extends SimpleChannelInboundHandler < byte[]> {
}

Categories

Resources