I am in the middle of learning Netty an started some tutorials using spring boot. My goal is to create an application which set up a tcp port for receiving messages and to present them over a rest api.
Most of the tutorials are saying that I should add something like this
serverChannel = serverBootstrap.bind(tcpPort).sync().channel().closeFuture().sync().channel();
to start netty.
When I do that, the rest services which I implemented are not working.
Now when I use the following code snippet to start the application:
serverChannel = serverBootstrap.bind(tcpPort).sync().channel();
everything seems to be working just fine.
Could someone explain me what might cause this issue?
Thanks
The first part start the server,
1) binding it on a TCP port,
2) wait for the server to be ready (socket is listening)
3) and return the associated channel.
serverBootstrap.bind(tcpPort).sync().channel();
(1) (2) (3)
The second part is to wait for the main channel (listening socket) to shutdown (closeFuture().sync()) where closeFuture gives you the "future" on "close" operation (meaning shutdown of the server socket), and sync waiting for this future to be done. channel() gives you back the very same channel than first time, except it is now closed.
So you might find this code in various example because generally you start the server (bind) in the main thread or so, and then if you don't wait for something, the main thread will end up, giving your JVM finishing, and therefore your server to stop immediately after starting.
So in general, what we do is:
start the server
add in the pipeline the necessary handlers to handle your business logic (and the network protocol of course)
then finish your main by waiting on closeFuture, such that, once in your business logic you get the order to shutdown, you close the main channel, and therefore your main thread is closing too.
See for instance Shutdown netty programmatically
Old, but I had same issue with my RestController not starting. Other answer helped solve it for me but here is full code for the Spring component.
import com.myserver.netty.handler.ClientInboundHandler;
import com.myserver.netty.handler.PacketDecoder;
import com.myserver.netty.handler.PacketEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
#Component
#Log4j2
public class NettyServer {
private EventLoopGroup masters = new NioEventLoopGroup();
private EventLoopGroup workers = new NioEventLoopGroup();
private Channel mainChannel;
#PostConstruct
public void start() {
try {
ServerBootstrap bootstrap = init();
mainChannel = bootstrap.bind(8484).sync().channel(); // save the main channel so we can cleanly close it when app is shutdown
log.info("Netty Server started......");
} catch (Exception e) {
e.printStackTrace();
}
}
#PreDestroy
public void stop() throws InterruptedException {
log.info("Shutting down netty server");
workers.shutdownGracefully().sync();
masters.shutdownGracefully().sync();
mainChannel.closeFuture().sync();
log.info("Shutdown complete");
}
private ServerBootstrap init() {
return new ServerBootstrap()
.group(masters, workers)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 5000)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new PacketDecoder())
.addLast(new ClientInboundHandler())
.addLast(new PacketEncoder());
}
});
}
}
Related
I wrote a basic java server class. When it handles the "shutdown" request, it calls server.stop(0) and the spins in place. Why is this happening?
I copied most of the code from this StackOverflow post.
The only significant modification to this code is that I added the server.stop(0).
Other facts: I am running this using java 8 and I am running this through IntelliJ.
package good.question.ask.questions.stackoverflow;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
public class ServerTester2
{
private HttpServer server = null;
public static void main(String[] args) throws Exception {
ServerTester2 serverTester2 = new ServerTester2();
serverTester2.start();
}
void start()
{
try {
server = HttpServer.create(new InetSocketAddress(8000), 0);
} catch (IOException e) {
e.printStackTrace();
}
server.createContext("/shutdown", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
class MyHandler implements HttpHandler
{
#Override
public void handle(HttpExchange t) throws IOException
{
String response = "This is the response";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
t.close();
System.out.println("Stopping Server...");
stop();
System.out.println("Server Stopped!");
}
}
void stop()
{
server.stop(0);
}
}
Currently, the server returns a response message to the client (I tested that using postman), and then prints "Stopping Server" to the console. After that, the server object seems to be shut down, because when I send it more requests it doesn't respond to them, however, the thread running the server continues to spin.
Minimally, I expected the server to reach this line of code
System.out.println("Server Stopped!");
but it never does.
More to the point, I expected the server thread to terminate but instead, it just spins.
Why is this happening? (Do I have a deadlock in the code somewhere?)
Is there a better way to handle server shutdown (using the httpserver library)?
Please see the updates below.
I have a Spring Boot application where I accept TCP/IP connections:
public MyClass implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
try (ServerSocket serverSocket = new ServerSocket(port)) {
while (true) {
Socket socket = serverSocket.accept();
new ServerThread(socket).start();
}
}
}
...
private class ServerThread extends Thread {
#Override
public void run() {
try (InputStream input = socket.getInputStream();
OutputStream output = socket.getOutputStream()) {
// Read line from input and call a method from service:
service.myMethod(lineConvertedToMyObject);
} catch {
...
}
}
}
}
Now this works fine, as it is. But when I introduce AspectJ to myMethod:
#Aspect
#Component
public class MyServiceAspect {
private static final Logger logger = LoggerFactory.getLogger(MyServiceAspect.class);
#Around(value = "execution(* com.package.to.MyService.myMethod(..))")
public MyObject rules(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
MyObject obj = (MyObject) joinPoint.proceed();
logger.debug("Took {} milliseconds", System.currentTimeMillis() - startTime);
return obj;
}
}
service.myMethod is not called and the thread is blocked. What am I missing?
Update:
So here's the deal: MyService, MyServiceImpl and MyServiceAspect are all in the same package. Moving MyServiceAspect into another package made it work.
Does this ring a bell for anyone? Happy to award the bounty to anyone explaining this behavior. Thanks!
Update 2:
Yet another solution: Adding #DependsOn(value = {"myServiceAspect"}) on top of MyServiceImpl again resolves the issue, still wondering why though.
Actual problem
As it was described by Alexander Paderin >> in his answer to the related question >> infinite loop in the afterPropertiesSet() was the thread blocker, since control wasn't return back to Spring in this case.
1. Working example with your samples (not actual after question edit)
Code samples you've provided do not contain issues directly, AspectJ declaration is fine.
First of all, please let me share working example: spring-aspectj-sockets. It is based on Spring 5.1.0 and AspectJ 1.9.1 (currently latest versions) and uses your samples, works independent of the location/package of MyServiceAspect.
2. Issue explanation
2.1. Intro
The most possible thread blocker in your samples is a call to ServerSocket.accept(), javadocs for this method says:
Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
There are 2 correct ways of handling accept():
To initialize connection first, e.g.:
serverSocket = new ServerSocket(18080);
clientSocket = new Socket("127.0.0.1", 18080); // initializing connection
Socket socket = serverSocket.accept(); // then calling accept()
Set up timeout to wait for acceptance:
serverSocket = new ServerSocket(18080);
serverSocket.setSoTimeout(5000); // 5 seconds timeout
Socket socket = serverSocket.accept(); // then calling accept()
NOTE: If within 5 seconds there will be no connections, accept() will throw exception, but will not block the thread
2.2. Assumption
I assume that you are using 1-st approach and somewhere you have a line which initializes the connection, i.e. clientSocket = new Socket("127.0.0.1", 18080);.
But it is called (e.g. if static declarations are used):
After serverSocket.accept() in case MyServiceAspect is located in the same package and
Before - in case MyServiceAspect is located in some other place
3. Debugging
I'm not sure if this is needed, have doubts because of bounty's description, let me cover this quickly just in case.
You can debug your application using Remote Debugging - it will cover aspects, child threads, services, etc. - you will only need to:
Run Java with specific arguments like it is described in this question >>
And connect to the specified debug port using IDE (steps for Eclipse are described in the same question)
I am trying to create multiple client connection to a java based socket server from another machine. Both server and client use Netty 4 for NIO. On server side, I used boss and worker group and its able to receive and server 100000 concurrent connection on a single linux box (after setting kernel parameters and ulimit).
However, I end up creating a new thread per connection on client side and that caused JVM thread limit exception.
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
public class TelnetClient
{
private Bootstrap b;
private NioEventLoopGroup loopGroup;
private TelnetConnectionInitializer tci;
public static void main(String[] args) throws Exception
{
System.out.println("TelnetClient:main:enter " + args[0]);
TelnetClient tc = new TelnetClient();
String countStr = args[0]; //number of connections to make
int count = Integer.valueOf(countStr);
for (int i=0; i < count; i++)
{
params.add(String.valueOf(i));
Runnable r = new ClientThread(tc);
new Thread(r).start();
}
System.out.println("TelnetClient:main:exit");
}
public TelnetClient()
{
System.out.println("TelnetClient:TelnetClient");
b = new Bootstrap();
loopGroup = new NioEventLoopGroup();
b = b.group(loopGroup);
b = b.channel(NioSocketChannel.class);
tci = new TelnetConnectionInitializer();
}
public void connect(String host, int port) throws Exception {
System.out.println("TelnetClient:connect:enter");
try {
b.handler(tci).connect(host, port).sync().channel().closeFuture().sync();
} finally {
b.group().shutdownGracefully();
}
System.out.println("TelnetClient:connect:exit");
}
}
/// Creating a new thread per connection,
/// Which seems the culprit of JVM exception, but couldn't found a way to implement boss / worker like solution on client side.
class ClientThread implements Runnable
{
TelnetClient myTc;
public ClientThread(TelnetClient tc)
{
myTc = tc;
}
public void run()
{
System.out.println("ClientThread:run");
try
{
myTc.connect("192.168.1.65", 4598); //Server running on different machine in local network
} catch (Exception e)
{
e.printStackTrace();
}
}
}
Can someone point me, how I can create multiple connections from client side using Netty, without spawning new thread per client. I tried one and only snippet found for similar condition in another post on stack overflow but in that, for me execution paused (entered into an infinite wait state) after first successful connection itself.
Thanks
The code looks to be correct apart from two important things - you have to share netty context by all the clients and work asynchronously.
I.e. initialize EvenetLoopGroup at the beginning and pass this single instance to every call to Bootstrap.group() for each client.
For asynchronous aproach avoid sync() on connect() future (not that much important) and mainly on close() future. The latter the code being suspended until the connection is closed.
I have the following code in my main application:
package acast;
import java.net.SocketException;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ACast {
private ConcurrentLinkedQueue<String> queue;
public ACast() throws SocketException{
queue = new ConcurrentLinkedQueue<String>();
UDPServer srv = new UDPServer(4321);
srv.addUDPacketListener(new UDPPacketListener() {
#Override
public void onPacketReceived(String packet) {
ACast.this.queue.offer(packet);
}
});
srv.start();
}
public static void main(String[] args) throws SocketException {
try{
new ACast();
}
catch(SocketException e){
//e.printStackTrace();
System.out.println("Socket allready opened. Can't start application");
System.exit(1);
}
}
}
My UDPServer extends Thread and calls onPacketReceived every time it receives an UDP datagram. I want my main app to do something every time a configured timeout passes since the last received datagram. I would like to avoid running a Thread that just checks the timeout from second to second. I would like to start a countdown thread exactly on the moment of the last received datagram and cancel any other ongoing timeout threads if available. Any help ?
A simple solution would be to start a Timer with the timeout task, and every time a new datagram is received, cancel the currently running timer and start a new one.
I would lose the asynchronicity altogether, and use blocking I/O with a read timeout.
I am using Undertow to create a simple application.
public class App {
public static void main(String[] args) {
Undertow server = Undertow.builder().addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange) throws Exception {
Thread.sleep(5000);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Hello World");
}
}).build();
server.start();
}
}
I open a browser tab on localhost:8080 and I open a second
tab also on localhost:8080
This time the first tab will wait 5 seconds, and the second will wait 10 seconds
Why is it so?
The HttpHandler is executing in an I/O thread. As noted in the documentation:
IO threads perform non blocking tasks, and should never perform blocking operations because they are responsible for multiple connections, so while the operation is blocking other connections will essentially hang. One IO thread per CPU core is a reasonable default.
The request lifecycle docs discuss how to dispatch a request to a worker thread:
import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.util.Headers;
public class Under {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender()
.send("Hello World");
}
})
.build();
server.start();
}
}
I noted that you won't necessarily get one worker thread per request - when I set a breakpoint on the header put I got about one thread per client. There are gaps in both the Undertow and the underlying XNIO docs so I'm not sure what the intention is.
Undertow uses NIO, which means that a single thread handles all the requests. If you want to do blocking operations in your request handler, you have to dispatch this operation to a worker thread.
In your example, you put the thread to sleep, which means tha any request handling is put to sleep, since this thread handles all requests.
However even if you dispatched the operation to worker thread and put that to sleep, you still would see the blocking issue you mention. This is because you open the same url in several tabs on the same browser. The browsers have an internal blocking of their own. If you open the same url in different tabs, the second url will start the request after the first has finished. Try any url you want to see for yourself. You can easily be confused with this browser behaviour.
The easiest thing to do would be to wrap your handler in a BlockingHandler.
import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.server.handlers.BlockingHandler;
import io.undertow.util.Headers;
public class Under {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(new BlockingHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender()
.send("Hello World");
}
})).build();
server.start();
}
}