I want to send large message between client and server with netty, but when I use netty for sending large message to server, In server I cannot get message complete for first time, in server I use ChannelHandlerAdapter when send large message from client method channelReadComplete run for two seconds, it must run for first time. Please see my client code and tell me my problem.
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel ch)
throws Exception {
ChannelPipeline p = ch.pipeline();
// if (sslCtx != null) {
// p.addLast(sslCtx.newHandler(ch.alloc(), HOST,
// PORT));
// }
System.out.println("initChannel-client");
p.addLast(new DiscardClientHandler(),
new LengthFieldBasedFrameDecoder(
100 * 1024, 0, 8));
}
});
// Make the connection attempt.
ChannelFuture f = b.connect(HOST, PORT).sync();
// // Wait until the connection is closed.
// // add by test
DiscardClient discardClient = new DiscardClient();
String message = discardClient.reafFile("D:\\log\\log1.txt");
ByteBuf encoded = f.channel().alloc().buffer(message.length());
encoded.writeBytes(message.getBytes());
f.channel().write(encoded);
f.channel().flush();
f.channel().closeFuture().sync();
} finally {
// group.shutdownGracefully();
}
Best Regards
Related
I am trying to use the following code which is an implementation of web sockets in Netty Nio. I have implment a JavaFx Gui and from the Gui I want to read the messages that are received from the Server or from other clients. The NettyClient code is like the following:
public static ChannelFuture callBack () throws Exception{
String host = "localhost";
int port = 8080;
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 {
ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(),
new ClientHandler(i -> {
synchronized (lock) {
connectedClients = i;
lock.notifyAll();
}
}));
}
});
ChannelFuture f = b.connect(host, port).sync();
//f.channel().closeFuture().sync();
return f;
}
finally {
//workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
ChannelFuture ret;
ClientHandler obj = new ClientHandler(i -> {
synchronized (lock) {
connectedClients = i;
lock.notifyAll();
}
});
ret = callBack();
int connected = connectedClients;
if (connected != 2) {
System.out.println("The number if the connected clients is not two before locking");
synchronized (lock) {
while (true) {
connected = connectedClients;
if (connected == 2)
break;
System.out.println("The number if the connected clients is not two");
lock.wait();
}
}
}
System.out.println("The number if the connected clients is two: " + connected );
ret.channel().read(); // can I use that from other parts of the code in order to read the incoming messages?
}
How can I use the returned channelFuture from the callBack from other parts of my code in order to read the incoming messages? Do I need to call again callBack, or how can I received the updated message of the channel? Could I possible use from my code (inside a button event) something like ret.channel().read() (so as to take the last message)?
By reading that code,the NettyClient is used to create connection(ClientHandler ),once connect done,ClientHandler.channelActive is called by Netty,if you want send data to server,you should put some code here. if this connection get message form server, ClientHandler.channelRead is called by Netty, put your code to handle message.
You also need to read doc to know how netty encoder/decoder works.
How can I use the returned channelFuture from the callBack from other parts of my code in order to read the incoming messages?
share those ClientHandler created by NettyClient(NettyClient.java line 29)
Do I need to call again callBack, or how can I received the updated message of the channel?
if server message come,ClientHandler.channelRead is called.
Could I possible use from my code (inside a button event) something like ret.channel().read() (so as to take the last message)?
yes you could,but not a netty way,to play with netty,you write callbacks(when message come,when message sent ...),wait netty call your code,that is : the driver is netty,not you.
last,do you really need such a heavy library to do network?if not ,try This code,it simple,easy to understanding
I have a very simple Server designed in Java using Netty. I have also written a simple client using Java NIO Package. I can connect the Netty Server with the client but when the message is sent to the server I am getting the following exceptions:
My Output:
New client connected: /127.0.0.1:1125 java.io.IOException: An existing connection was forcibly closed by the remote host at sun.nio.ch.SocketDispatcher.read0(Native Method) at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43) at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223) at sun.nio.ch.IOUtil.read(IOUtil.java:192) at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380) at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288) at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1100) at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:372) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:123) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:644) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:579) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:496) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:458) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138) at java.lang.Thread.run(Thread.java:745)
My Server Program:
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(newLengthFieldBasedFrameDecoder(Integer.MAX_VALUE,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(1125).start();
}
}
My ServerHandler:
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();
}
}
My NIO Java Client:
public class NIOJavaClient {
public static void main(String[] args) throws IOException, InterruptedException {
InetSocketAddress addr = new InetSocketAddress("localhost", 1125);
SocketChannel client = SocketChannel.open(addr);
System.out.println("Connecting to Server on port 1125...");
int i=0;
while(i<10){
byte[] message = new String("Hi Server\n").getBytes();
ByteBuffer buffer = ByteBuffer.wrap(message);
client.write(buffer);
buffer.clear();
i++;
}
client.close();
}
}
Now My required things are:
1) I can't send message from my client to server.Present I am using a Java NIO Client (not Netty). In future I may send message in bytes from a C# client to the netty server. Is it possible and if so how to do it?
2) I am using the LengthFieldBasedFrameDecoder and LengthPrepender to eliminate half strings (the strings that are sent from NETTY client are cut to a size everytime). I am successfully receiving the message when I use a Netty Client but when I use a different Client designed in Mina or C# I am getting an Exception: length frame exceeded. How can I eliminate this?
In a brief manner I want to connect a client designed in any language which sends bytes to the Netty Server and also eliminate the half strings. This is a critical situation for me. Any help would be really appreciable.
Since you are using the LengthFieldBasedFrameDecoder in your code, this means that you need to send your packets from simple program in the format this handler accepts, namely, prepended by a 4 byte value in network order that gives the length of the upcoming data.
Example for your NIO client
byte[] message = new String("Hi Server\n").getBytes();
byte[] fullMessage = new byte[message.length + 4];
fullMessage[0] = (byte)(message.length >> 24);
fullMessage[1] = (byte)(message.length >> 16);
fullMessage[2] = (byte)(message.length >> 8);
fullMessage[3] = (byte)message.length;
System.arraycopy(message, 0, messageFull, 4, message.length);
ByteBuffer buffer = ByteBuffer.wrap(fullMessage);
client.write(buffer);
buffer.clear();
There seems to be a better way, since your protocol work on lines ended with a newline (but this may also be caused by your attempts to debug the issue), instead of prefixing the packets with a length, just wait for a newline character using the DelimiterBasedFrameDecoder handler, use it like this:
ch.pipeline.addLast(new DelimiterBasedFrameDecoder(Delimiters.lineDelimiter()))
// Don't forget to remove your old 2 handlers
I need to build a client that initiates a TCP connection with a server and upon response it sends a hand shake request every 10 seconds and gets a response from the server. The server will be able to send another type of request which my client needs to read and act upon. I am using netty 4.0.26.Final.
I have built a client and a dummy server but I am facing an issue which possibly means that there is something I have not understood.
My Client:
String host = "localhost";
int port = 9884;
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 MyChannelPipeline());
// Start the client.
ChannelFuture f = b.connect(host, port).sync();
String line = "line";
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while (!line.equals("exit")) {
line = in.readLine();
if (line == null) {
break;
}
}
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
}
The ChannelPipleline:
#Override
public void initChannel(Channel ch) throws Exception {
ChannelPipeline channelPipeline = ch.pipeline();
//Encodes every request send from the client to the server
channelPipeline.addLast("clientRequestEncoder", new ClientRequestEncoder());
//Implements channelActive and exceptionCaught
channelPipeline.addLast("initialRequestHandler", new InitialRequestHandler());
channelPipeline.addLast("byteArrayDecoder", new ByteArrayDecoder());
channelPipeline.addLast("serverResponseDecoder", new ServerResponseDecoder());
channelPipeline.addLast("serverRequestDecoder", new ServerRequestDecoder());
//Reads the responses from the client requests AND
//reads the inbound requests from the server - Implements channelRead
//and exceptionCaught
channelPipeline.addLast("myResponseHandler", new MyResponseHandler());
}
The problem is that when I flush the response to the server (in MyResponseHandler) and exception is caught in InitialRequestHandler:
ERROR=java.lang.UnsupportedOperationException:unsupported message type: ServerResponse (expected: ByteBuf, FileRegion)
I don't see why the response is not flushed back to the server while the hand shake request is always properly flushed. In both write and flush I have used a ChannelFuture and onOperationComplete this listener f.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE); is fired on failure.
Can I use two handlers in the same pipeline or is it bad practise? Moreover how should I fire an unregister event triggered by user input?
I solved this using one Handler that overrides channelActive and channelRead and I rearranged the encoders and decoders properly. I also solved the "unregister event triggered by user input" this way:
String line = "line";
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
do {
logger.info("You typed: " + line + ". Please type 'exit' to terminate the program!");
line = in.readLine();
} while (!line.equals("exit"));
logger.info("You typed: " + line + ". Please wait until the application is successfully shutdown...");
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
myChannelPipeline.getMyClientHandler().sendDisconnectRequest(future);
}
});
In sendDisconnectReqeust I send the final request and when I get the final response (in channelRead of MyHandler) I call disconnect on the pipeline:
ChannelPromise cp = new DefaultChannelPromise(ctx.channel());
ctx.channel().pipeline().disconnect(cp);
However I still have other issues with inbound requests that are never received by my client.
I am trying to simulate a 10000 client connection at the same time to server using Netty. When 956 clients connect to the server everything work great, but the 957 client cause an error exception.
Note: I am running the server and the clients at the same machine(win7 8GB ram, i7-CPU)
The error:
java.lang.IllegalStateException: failed to create a child event loop
io.netty.channel.ChannelException: failed to open a new selector
My code:
try {
con.connect();
} catch (Exception e) {
logger.error("Client: error connect to ip {} and port {}, ",id, ip, port,e);
return;
}
The code of connect method is:
public void connect() {
workerGroup = new NioEventLoopGroup();
Bootstrap bs = new Bootstrap();
bs.group(workerGroup).channel(NioSocketChannel.class);
bs.handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(0, 0, 300));
ch.pipeline().addLast("idleStateActionHandler", new IdleStateEventHandler());
ch.pipeline().addLast("logger", new LoggingHandler());
ch.pipeline().addLast("commandDecoder", new CommandDecoder());
ch.pipeline().addLast("commandEncoder", new CommandEncoder());
}
});
You should use the same NioEventLoopGroup instance for each connect call. Otherwise you will create a lot of Threads.
I have some clients, they communicate with one server and I need that server forward the message to another second server. Then, receive the message from the second server and send to the client.
With this method, I achieve connecting to the second server but it doesn't receive the message and throws me the following exception:
EXCEPTION: java.nio.channels.NotYetConnectedException. java.nio.channels.NotYetConnectedException
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws IOException, Exception {
response = "hola" + "\r\n";
Main.creaLog("Mensaje recibido del conc: " + e.getMessage().toString());
Main.creaLog("Mensaje enviado al servidor : " + response);
ClientBootstrap bootstrap1 = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Configure the pipeline factory.
//bootstrap1.setPipelineFactory(new CLIENTE.ClientePipelineFactory());
bootstrap1.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(new ClienteHandler());
}
});
final ChannelFuture future = bootstrap1.connect(new InetSocketAddress("172.16.10.14", 12355));
Channel channel = future.getChannel();
if (channel.isWritable()) {
ChannelFuture lastWriteFuture = channel.write(e.getMessage().toString() + "\r\n");
}
close = true;
// We do not need to write a ChannelBuffer here.
// We know the encoder inserted at TelnetPipelineFactory will do the conversion.
ChannelFuture future = e.getChannel().write(response + "\r\n");
//CIERRA LA CONEXION
if (close) {
future.addListener(ChannelFutureListener.CLOSE);
}
}
I'm very thanksful if anybody can help me.
Have a look at Netty Proxy example
Right now, you are basically attempting to connect to the remote server on every message that you receive. This probably isn't what you want. You might want to connect to the remote server only once (i.e. outbound channel in Netty proxy example) and forward a new incoming message to that specific channel.