I try to create a client which will retry connect when previous connection timeout. This program tries to connect to localhost:8007 which port 8007 is without any service, so the program will retry after connection time out. But this code will free after running for a while. The program freezes when there are about 3600 threads. I expect it will continue to retry rather than it will freeze.
The standard output's last output is "retry connect begin".
Does anyone know the reason why it will freeze?
JProfiler: program's Thread statistic, shows 2 threads are blocked on java.lang.ThreadGroup:
JProfiler showing program's Thread statistic
public final class EchoClient2 {
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", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
public static void main(String[] args) throws Exception {
// Configure SSL.git
EchoClient2 echoClient2 = new EchoClient2();
echoClient2.connect();
}
public void connect() throws InterruptedException {
final SslContext sslCtx;
// Configure the client.
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(HOST, PORT);
f.addListener(new ConnectionListener());
System.out.println("add listener");
f.sync();
System.out.println("connect sync finish");
// Wait until the connection is closed.
f.channel().closeFuture().sync();
System.out.println("channel close");
} finally {
// Shut down the event loop to terminate all threads.
//group.shutdownGracefully();
}
}
}
public class ConnectionListener implements ChannelFutureListener {
#Override
public void operationComplete(ChannelFuture channelFuture) throws Exception {
System.out.println("enter listener");
EventLoop eventLoop = channelFuture.channel().eventLoop();
eventLoop.schedule(new Runnable() {
#Override
public void run() {
try {
System.out.println("retry connect begin");
new EchoClient2().connect();
System.out.println("retry connect exit");
} catch (InterruptedException e) {
System.out.println(e);
e.printStackTrace();
}
}
}, 10, TimeUnit.MILLISECONDS);
System.out.println("exit listener");
}
}
Related
I wonder how I could shut down a netty client
public void disconnect() {
try {
bootstrap.bind().channel().disconnect();
dataGroup.shutdownGracefully();
System.out.println(Strings.INFO_PREF + "Disconnected from server and stopped Client.");
} catch (Exception ex) {
ex.printStackTrace();
}
}
You need to hold the reference to the client Channel and EventLoopGroup during the start of the client and close it when necessary.
public void start() {
NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup(1);
Bootstrap b = new Bootstrap();
b.group(nioEventLoopGroup)
.channel(NioSocketChannel.class)
.handler(getChannelInitializer());
this.nioEventLoopGroup = nioEventLoopGroup;
this.channel = b.connect(host, port).sync().channel();
}
//this method will return execution when client is stopped
public ChannelFuture stop() {
ChannelFuture channelFuture = channel.close().awaitUninterruptibly();
//you have to close eventLoopGroup as well
nioEventLoopGroup.shutdownGracefully();
return channelFuture;
}
The Main class:
Main {
public static void main(String[] args) {
final HTTPServer server = new HTTPServer(9999);
server.start();
System.out.println("Server started!");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
server.stop();
System.out.println("Server stopped!");
}));
}
}
HTTPServer {
// for debug
private static int threadNumber;
private final int port;
private Thread listenThread;
public HTTPServer(int port) {
this.port = port;
}
void start() {
listenThread = new Thread() {
#Override
public void run() {
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (!interrupted()) {
Socket socket = serverSocket.accept();
threadNumber++;
System.out.println(threadNumber+"==========================");
socket.getOutputStream().write(("\"HTTP/1.1 200 OK\\r\\n\"Connection: close\r\n\r\n").getBytes());
// socket.getOutputStream().write("abrakadabra".getBytes());
socket.close();
Thread.sleep(1000);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
};
listenThread.start();
}
void stop() {
listenThread.interrupt();
}
}
The above code after one client request prints:
Server started!
1==========================
2==========================
When i replace socket.getOutputStream().write(("\"HTTP/1.1 200 OK\\r\\n\"Connection: close\r\n\r\n").getBytes()); with socket.getOutputStream().write("abrakadabra".getBytes());, programm prints:
Server started!
1==========================
2==========================
3==========================
I am using Netty 5.0.
I have a complementary client bootstrap for which I took the SecureChatClient.java example from netty github.
Wenn I send messages from the client bootstrap to the server it works perfectly fine. When I try to send messages from the server bootstrap to the client (after successfully initiating a connection/channel through the client first) I get a java.lang.UnsupportedOperationException without any further information on it. Sending messages from server to client is done via code above.
Is a serverbootstrap for receiving only?
Is a serverbootstrap not meant to be able to write messages back to the client as shown above? By that I mean, messages can enter a ChannelPipeline from a socket up through the ChannelHandlers, but only the ChannelHandlers are supposed to be writing responses back down the ChannelPipeline and out the socket. So in a ServerBootstrap a user is not meant to be able to send messages down the ChannelPipeline from outside the Pipeline. (Hope that makes sense)
Or am I simply missing something?
My code follows:
// Ports.
int serverPort = 8080;
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
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());
}
})
.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();
System.out.println("Server: Running!");
// Read commands from the stdin.
ChannelFuture lastWriteFuture = null;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
while(true)
{
String line = in.readLine();
if (line == null) break;
ByteBuf getOut = buffer(64);
getOut.writeBytes(line.getBytes());
// Sends the received line to the server.
lastWriteFuture = ch.writeAndFlush(getOut);
lastWriteFuture.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture 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 (InterruptedException | UnsupportedOperationException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
I started using the following example: https://github.com/netty/netty/tree/4.1/example/src/main/java/io/netty/example/securechat
My problem is that I get the following exception when calling ch.writeAndFlush:
java.lang.UnsupportedOperationException
at io.netty.channel.socket.nio.NioServerSocketChannel.filterOutboundMessage(NioServerSocketChannel.java:184)
at io.netty.channel.AbstractChannel$AbstractUnsafe.write(AbstractChannel.java:784)
at io.netty.channel.DefaultChannelPipeline$HeadContext.write(DefaultChannelPipeline.java:1278)
at io.netty.channel.ChannelHandlerInvokerUtil.invokeWriteNow(ChannelHandlerInvokerUtil.java:158)
at io.netty.channel.DefaultChannelHandlerInvoker$WriteTask.run(DefaultChannelHandlerInvoker.java:440)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:328)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.internal.chmv8.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1412)
at io.netty.util.internal.chmv8.ForkJoinTask.doExec(ForkJoinTask.java:280)
at io.netty.util.internal.chmv8.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:877)
at io.netty.util.internal.chmv8.ForkJoinPool.scan(ForkJoinPool.java:1706)
at io.netty.util.internal.chmv8.ForkJoinPool.runWorker(ForkJoinPool.java:1661)
at io.netty.util.internal.chmv8.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:126)
You cannot write to a ServerChannel, you can only connect to normal channels. Your call to writeAndFlush is failing for this reason.
To send a message to every client, you should store the channel of every client inside a ChannelGroup and invoke writeAndFlush() on that.
A quick way to do this is adding another handler to your ServerBootstrap that puts the incoming connections inside the ChannelGroup, a quick implementation of this would be this:
// In your main:
ChannelGroup allChannels =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
// In your ChannelInitializer<SocketChannel>
ch.pipeline().addLast("grouper", new GlobalSendHandler());
// New class:
public class MyHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
allChannels.add(ctx.channel());
super.channelActive(ctx);
}
}
Then we can call the following to send a message to every connection, this returns a ChannelGroupFuture instead of a normal ChannelFuture:
allChannels.writeAndFlush(getOut);
Your total code would look like this with the fixes from above:
// Ports.
int serverPort = 8080;
ChannelGroup allChannels =
new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
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();
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 = 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 (InterruptedException | UnsupportedOperationException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
I think Netty Server has no decoder, encoder.
if you want to send String data,
serverBootstrap.group(bossGroup, workerGroup).childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline channelPipeline = channel.pipeline();
channelPipeline.addLast("String Encoder", new StringEncoder(CharsetUtil.UTF_8));
channelPipeline.addLast("String Decoder", new StringDecoder(CharsetUtil.UTF_8));
}
});
Add your server's Initializer!
Here is my client side source code:
public class Client
{
Server server;
Logger logger;
ChannelHandlerContext responseCtx;
public Client(String host, int port, int mode, String fileName)
{
server=null;
EventLoopGroup group = new NioEventLoopGroup();
try
{
Bootstrap b = new Bootstrap();
b.group(group);
b.channel(NioSocketChannel.class);
b.remoteAddress(new InetSocketAddress(host, port));
b.handler(new MyChannelInitializer(server, mode,fileName));
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
System.out.println("client started");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
try {
group.shutdownGracefully().sync();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Calendar endTime=Calendar.getInstance();
System.out.println("client stopped "+endTime.getTimeInMillis());
}
}
public static void main(String[] args) throws Exception
{
#SuppressWarnings("unused")
Client c=new Client("localhost",1234,MyFtpServer.SENDFILE,"D:\\SITO3\\Documents\\Xmas-20141224-310.jpg");
}
}
Here is my File Transfer Complete Listener source code:
public class FileTransferCompleteListener implements ChannelFutureListener
{
Server server;
public FileTransferCompleteListener(Server server)
{
this.server=server;
}
#Override
public void operationComplete(ChannelFuture cf) throws Exception
{
Calendar endTime=Calendar.getInstance();
System.out.println("File transfer completed! "+endTime.getTimeInMillis());
if(server!=null)
server.stop();
else
cf.channel().close();
}
}
Here is the execution result:
File transfer completed! 1451446521041
client started
client stopped 1451446523244
I want to know why it takes about 2 second to close connection.
Is it any way to reduce it?
thank you very much
Take a look at shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit), you can specify the quietPeriod, by default it is a couple of seconds.
I’m not sure what the implications are if you shorten this.
I'm trying to implement OSGI bundle with network server which uses network sockets.
This is the complete source code: http://www.2shared.com/file/RMXby331/CB_27.html
This is the Activator:
package org.DX_57.osgi.CB_27.impl;
import java.util.Properties;
import org.DX_57.osgi.CB_27.api.CBridge;
import org.DX_57.osgi.CB_27.impl.EchoServer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
public class CBridgeApp implements BundleActivator {
public void start(BundleContext bc) throws Exception {
ServiceRegistration registerService = bc.registerService(CBridge.class.getName(), new CBridgeImpl(), new Properties());
EchoServer();
}
public void stop(BundleContext bc) throws Exception {
boolean ungetService = bc.ungetService(bc.getServiceReference(CBridge.class.getName()));
}
private void EchoServer() {
EchoServer method = new EchoServer();
}
}
This is the source code if the Java Network server:
package org.DX_57.osgi.CB_27.impl;
import java.net.*;
import java.io.*;
public class EchoServer
{
ServerSocket m_ServerSocket;
public EchoServer()
{
try
{
// Create the server socket.
m_ServerSocket = new ServerSocket(12111);
}
catch(IOException ioe)
{
System.out.println("Could not create server socket at 12111. Quitting.");
System.exit(-1);
}
System.out.println("Listening for clients on 12111...");
// Successfully created Server Socket. Now wait for connections.
int id = 0;
while(true)
{
try
{
// Accept incoming connections.
Socket clientSocket = m_ServerSocket.accept();
// accept() will block until a client connects to the server.
// If execution reaches this point, then it means that a client
// socket has been accepted.
// For each client, we will start a service thread to
// service the client requests. This is to demonstrate a
// multithreaded server, although not required for such a
// trivial application. Starting a thread also lets our
// EchoServer accept multiple connections simultaneously.
// Start a service thread
ClientServiceThread cliThread = new ClientServiceThread(clientSocket, id++);
cliThread.start();
}
catch(IOException ioe)
{
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
}
public static void main (String[] args)
{
new EchoServer();
}
class ClientServiceThread extends Thread
{
Socket m_clientSocket;
int m_clientID = -1;
boolean m_bRunThread = true;
ClientServiceThread(Socket s, int clientID)
{
m_clientSocket = s;
m_clientID = clientID;
}
public void run()
{
// Obtain the input stream and the output stream for the socket
// A good practice is to encapsulate them with a BufferedReader
// and a PrintWriter as shown below.
BufferedReader in = null;
PrintWriter out = null;
// Print out details of this connection
System.out.println("Accepted Client : ID - " + m_clientID + " : Address - " +
m_clientSocket.getInetAddress().getHostName());
try
{
in = new BufferedReader(new InputStreamReader(m_clientSocket.getInputStream()));
out = new PrintWriter(new OutputStreamWriter(m_clientSocket.getOutputStream()));
// At this point, we can read for input and reply with appropriate output.
// Run in a loop until m_bRunThread is set to false
while(m_bRunThread)
{
// read incoming stream
String clientCommand = in.readLine();
System.out.println("Client Says :" + clientCommand);
if(clientCommand.equalsIgnoreCase("quit"))
{
// Special command. Quit this thread
m_bRunThread = false;
System.out.print("Stopping client thread for client : " + m_clientID);
}
else
{
// Echo it back to the client.
out.println(clientCommand);
out.flush();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
// Clean up
try
{
in.close();
out.close();
m_clientSocket.close();
System.out.println("...Stopped");
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
}
}
}
When I try to deploy the bundle on Glassfish server the application server hangs but I can connect to the java network server using the java client. It seems that there is a infinite loop. I need help to fix the code.
Best wishes
Your bundle activator start method never returns, because you're calling constructor of your service with infinite loop. A good practice is to return as fast as possible from bundle activators.
Here is an idea how to rewrite your code:
public class EchoServer {
private volatile boolean started;
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
started = true;
try {
m_ServerSocket = new ServerSocket(12111);
} catch(IOException ioe) {
System.out.println("Could not create server socket at 12111. Quitting.");
System.exit(-1);
}
System.out.println("Listening for clients on 12111...");
// Successfully created Server Socket. Now wait for connections.
int id = 0;
while (started) {
try {
Socket clientSocket = m_ServerSocket.accept();
ClientServiceThread cliThread = new ClientServiceThread(clientSocket, id++);
cliThread.start();
} catch(IOException ioe) {
System.out.println("Exception encountered on accept. Ignoring. Stack Trace :");
ioe.printStackTrace();
}
}
}
}).start();
}
public void stop() {
started = false;
}
}
Activator
public class CBridgeApp implements BundleActivator {
private EchoServer method;
public void start(BundleContext bc) throws Exception {
...
method = new EchoServer();
method.start();
}
public void stop(BundleContext bc) throws Exception {
...
method.stop();
}
}