How to use multiple ServerBootstrap objects in Netty - java

I am trying to use Netty (4.0.24) to create several servers (several ServerBootstraps) in one application (one main method). I saw this question/answer but it leaves many questions unanswered:
Netty 4.0 multi port with difference protocol each port
So here are my questions:
The above answer suggests that all we need to do is create multiple ServerBootstrap objects and bind() to each. But most of the code examples I see for a single ServerBootstrap will then call something like this:
try {
b.bind().sync().channel().closeFuture().sync();
}
finally {
b.shutdown();
}
So doesn't the sync() call result in the ServerBootstrap b blocking? So how can we do this for multiple ServerBootstraps? And what happens if we do not call sync()? Is the set of sync calls only for being able to gracefully shutdown the server with b.shutdown()? If so, is there any way to gracefully shutdown multiple ServerBootstraps?
Also, I don't understand what happens when we just call bind() without calling sync(). Does the server somehow keep running? How do we shut it down gracefully?
Obviously I'm pretty confused about how all this works, and sadly Netty documentation is really lacking in this regard. Any help would be greatly appreciated.

Following example you referenced and adding your question on sync() method, here an example code:
EventLoopGroup bossGroup = new NioEventLoopGroup(numBossThreads);
EventLoopGroup workerGroup = new NioEventLoopGroup(numWorkerThreads);
ServerBootstrap sb1 = null;
ServerBootstrap sb2 = null;
ServerBootstrap sb3 = null;
Channel ch1 = null;
Channel ch2 = null;
Channel ch3 = null;
try {
sb1 = new ServerBootstrap();
sb1.group(bossGroup, workerGroup);
...
ch1 = sb1.bind().sync().channel();
sb2 = new ServerBootstrap();
sb2.group(bossGroup, workerGroup);
...
ch2 = sb2.bind().sync().channel();
sb3 = new ServerBootstrap();
sb3.group(bossGroup, workerGroup);
...
ch3 = sb3.bind().sync().channel();
} finally {
// Now waiting for the parent channels (the binded ones) to be closed
if (ch1 != null) {
ch1.closeFuture().sync();
}
if (b1 != null) {
b1.shutdownGracefully();
}
if (ch2 != null) {
ch2.closeFuture().sync();
}
if (b2 != null) {
b2.shutdownGracefully();
}
if (ch3 != null) {
ch3.closeFuture().sync();
}
if (b3 != null) {
b3.shutdownGracefully();
}
So now on the explanations (I try):
The bind() command creates the listening corresponding socket. It returns immediately (not blocking) so the parent channel might not be yet available.
The first sync() command (bind().sync()) waits for the binding to be done (if an exception is raised, then it goes directly to the finally part). At this stage, the channel is ready and listening for new connections for sure.
The channel() command gets this listening channel (the parent one, connected to no one yet). All clients will generate a "child" channel of this parent one.
In you handler, after some event, you decide to close the parent channel (not the child one, but the one listening and waiting for new socket). To do this close, just call parentChannel.close() (or from a child channel child.parent().close()).
The closeFuture() command is getting the future on this closing event.
When this future is over (done), this is when the last sync() command (closeFuture().sync()) will take place.
Once the parent channel is closed, you can ask for a gracefully shutdown of the binded channel.
So doing this way (waiting for the closeFuture then shutdownGracefully) is a clean way to shutdown all resources attached to this ServerBootstrap.
Of course you can change a bit the things. For instance, not getting the channel first but only later when you want to block before gracefully shutdown.
EventLoopGroup bossGroup = new NioEventLoopGroup(numBossThreads);
EventLoopGroup workerGroup = new NioEventLoopGroup(numWorkerThreads);
ServerBootstrap sb1 = null;
ServerBootstrap sb2 = null;
ServerBootstrap sb3 = null;
ChannelFuture cf1 = null;
ChannelFuture cf2 = null;
ChannelFuture cf3 = null;
try {
sb1 = new ServerBootstrap();
sb1.group(bossGroup, workerGroup);
...
cf1 = sb1.bind();
sb2 = new ServerBootstrap();
sb2.group(bossGroup, workerGroup);
...
cf2 = sb2.bind();
sb3 = new ServerBootstrap();
sb3.group(bossGroup, workerGroup);
...
cf3 = sb3.bind();
} finally {
// Now waiting for the parent channels (the binded ones) to be closed
if (cf1 != null) {
cf1.sync().channel().closeFuture().sync();
}
if (cf2 != null) {
c2.sync().channel().closeFuture().sync();
}
if (cf3 != null) {
cf3.sync().channel().closeFuture().sync();
}
if (b1 != null) {
b1.shutdownGracefully();
}
if (b2 != null) {
b2.shutdownGracefully();
}
if (b3 != null) {
b3.shutdownGracefully();
}
This way you don't block at all while opening all 3 channels, but then wait for all 3 to be done before shutdown them.
Finally, if you don't block on bind() event then on closeFuture() event, it's up to you to define how you will wait after the sbx.bind() commands and before to shutdown the ServerBootstraps.

public static void main(String[] args) {
new Thread(new Runnable(){
#Override
public void run() {
//{...} ServerBootstrap 1
}
}).start();
new Thread(new Runnable(){
#Override
public void run() {
//{...} ServerBootstrap 2
}
}).start();
new Thread(new Runnable(){
#Override
public void run() {
//{...} ServerBootstrap 3
}
}).start();
}

Related

How to make the accept() function non-blocking?

My server is listening to 2 ports ,and it should execute separate functions on each port simultaneously.
my problem is ,that the server blocks until the client of the first port is connected first.
For example: if a second client tried to connect to the 2nd port before a client connects to the 1st port ,it won't let it connect.
I created 2 classes that extends to thread class,so they should wait to any client in parallel instead of blocking what's after them.
But it doesn't seem to work as i'm expecting.
public static void main(String[] args) throws Exception {
System.out.println("server is running.");
int clientNumber = 0;
ServerSocket listenerTrans = new ServerSocket(9899);
ServerSocket listenerDeter = new ServerSocket(9898);
try {
while (true) {
new Deteriment(listenerDeter.accept(), clientNumber++).start();
new Transpose(listenerTrans.accept(), clientNumber++).start();
}
} finally {
listenerTrans.close();
listenerDeter.close();
}
}
Deteriment and Transpose are my classes that extend to thread class.
I want that the listenerDeter.accept() not to block the listenerTrans.accept(), i want that both of the thread's accept() happen in parallel.
Also why isn't it happening in parallel in my code?
The answer is to use a ServerSocketChannel and a Selector. The Selector allows your application to multiplex I/O on multiple channels using a single thread. It can be used in clocking or non-blocking mode
Here is an example (borrowed from How java nio ServerSocketChannel accept works? and adapted for your use-case):
// Create the 2 server socket channels
ServerSocketChannel server1 = ServerSocketChannel.open();
ServerSocketChannel server2 = ServerSocketChannel.open();
// Configure channels for nonblocking I/O
server1.configureBlocking(false);
server2.configureBlocking(false);
// Bind channels' IP and port
server1.socket().bind(new java.net.InetSocketAddress(host, 9899));
server2.socket().bind(new java.net.InetSocketAddress(host, 9898));
// Create the selector
Selector selector = Selector.open();
// Register channels to selector (type OP_ACCEPT)
SelectionKey key1 = server1.register(selector, SelectionKey.OP_ACCEPT);
SelectionKey key2 = server2.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // blocks until one or more of the registered channels
// has actionable I/O
Iterator it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey selKey = (SelectionKey) it.next();
if (selKey.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) selKey.channel();
SocketChannel sc = ssc.accept();
if (selKey.equals(key1)) {
new Deteriment(sc.socket() ...).start();
} else {
new Transpose(sc.socket(), ...).start();
}
}
}
}
(Caveats: 1: not tested, 2: could be more elegant, 3: possible resource leaks, 4: you really should be using a thread pool / executor rather than firing off new threads by hand)
So, first of all if you like it to be async you need to use separate thread for every ServerSocket what u declare. Why? Becouse by the conception java.net was blocking not scalable way of dealing with net thinks. If you like it to be non-blocking more scalable but less abstrac (I mean you will allocate buffers ^^) you should look for java nio instead.
**EDIT: **
I little modyf your code it should make job done but its improvable i mean its not the most elegent version ^^
public static void main(String[] args) throws Exception {
System.out.println("server is running.");
final int[] clientNumber = {0};
ServerSocket listenerTrans = new ServerSocket(9899);
ServerSocket listenerDeter = new ServerSocket(9898);
try {
ExecutorService ex = Executors
.newFixedThreadPool(2);
ex.execute(
() -> {
try {
Socket s = listenerDeter.accept();
new Deteriment(s, clientNumber[0]++).start();
} catch (IOException e) {
e.printStackTrace();
}
}
);
ex.execute(
() -> {
try {
Socket s = listenerDeter.accept();
new Transpose(s, clientNumber[0]++).start();
} catch (IOException e) {
e.printStackTrace();
}
}
);
} finally {
//listenerTrans.close();
//listenerDeter.close();
}
}

UnsupportedOperationException when sending messages through ServerBootstrap ChannelPipeline in Netty

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!

Java TCPIP Detecting Full Packet Message

I have developed an application using TCPIP in Java though the use of ServerSockets and Sockets. The application is a Listener that listens for messages arriving at a specified port. When a message arrives it is processed and various things are done. My company has provided a small application that acts as a client that sends a message. Recently, they have extended the small application that that sends multiple messages in one go.
Now, my application that is the Listener does not fully receive the multiple messages. I have tried to increase the default buffer on the ServerSocket and still I don't receive the full message. How can this be debugged? The company has a working version of another application that instantly sends the messages and they are all received instantly. The Listener application receives one message in one go. The below code is a sample:
#Startup
#Singleton
public class Listener {
private ServerSocket serverSocket;
private Socket socket;
#Resource
private ScheduledExecutorService executor;
#PostConstruct
public void init() {
serverSocket = new ServerSocket(portNumber);
Runnable runnable = new Runnable() {
public void run() {
try {
if(socket == null) {
socket = serverSocket.accept();
socket.setKeepAlive(true);
}
else if(socket.isClosed()) {
socket = serverSocket.accept();
socket.setKeepAlive(true);
}
char[] messages = buildMessage(socket.getInputStream());
}
catch(Exception e) {
System.out.println("Exception occurred");
e.printStackTrace();
}
}
};
executor.scheduleAtFixedRate(runnable, 0, 0, TimeUnit.SECONDS);
}
public char[] buildMessage(InputStream inputStream) throws Exception {
StringBuilder message = null;
char[] values = null;
if(inputStream != null) {
message = new StringBuilder();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
int byteRead = bufferedInputStream.read();
while(byteRead != -1) {
char value = (char) byteRead;
message.append(value);
// check how many bytes available
if(bufferedInputStream.available() != 0) {
byteRead = bufferedInputStream.read();
}
else {
// to avoid blocking of data
break;
}
}
}
}
}
There is no such thing as a message in TCP.
It is a byte stream, and it can be received in chunks as small as a byte at a time.
If you want messages you must implement them yourself, by reading until you have everything you need.
That may require altering or providing an application protocol such as lines, XML, length-word prefixes, etc., so you know where a message stops.

java thread System.in how can i "wait for console commands"

Let's say I got System.in
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
result = br.readLine();
while (!result.isEmpty()) {
if (result.equalsIgnoreCase("exit")) {
userStr="exit";
System.exit(0);
} else if (result.equalsIgnoreCase("list")) {
userStr="list";
} else if (result.equalsIgnoreCase("kill")) {
userStr="kill";
} else if (result.equalsIgnoreCase("help")) {
userStr="help";
}
and
ServerSocket socketListener = new ServerSocket(port);
while (true) {
Socket client = socketListener.accept();
new ServerThread(client,userStr); //pass userStr to Thread
}
i don't understand how can i "wait for console commands" and pass them to active Thread. I need to accept() clients, pass them to thread. If I entered a command into the server console like for example; "kill Username"(disconnect user) or "list"(list of Usernames)
my server should pass commands to threads.
p/s I need manage server, manage implemented by entering the console commands.
As easy solution you can block you thread untill it will recieve a task to execute :
class Task implements Runnable {
AtomicReference<String> atomicReference = new AtomicReference<String>(null);
#Override
public void run() {
while (true) {
String command = atomicReference.getAndSet(null);
if (command != null) {
//do staff with command
}
}
}
public void executeCommand(String command) {
atomicReference.set(command);
}
}
Use it like this:
ServerSocket socketListener = new ServerSocket(port);
Task task = new Task();
new Thread(task).start();
while (true) {
Socket client = socketListener.accept();
task.executeCommand(userCommand);
}
But if you need more complex solution I can advice you to read about Java Concurrency package:
Avesome book about that
Good article

Exit from a thread

I have the following block of code:
public void startListening() throws Exception {
serverSocket = new DatagramSocket(port);
new Thread() {
#Override
public void run() {
System.out.print("Started Listening");
byte[] receiveData = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
while (!stopFlag) {
try {
serverSocket.receive(receivePacket);
String message = new String(receivePacket.getData());
System.out.println("RECEIVED: " + message);
} catch (Exception ex) {
System.out.print("Execption :" + ex.getMessage());
}
}
}
}.start();
}
public void stopListening() {
this.stopFlag = true;
}
Suppose I set stopFlag to true. serverSocket.receive(receivePacket); will wait until it receives a packet. What should I do if I want the thread to exit as soon as stopFlag is set to true.
I had the same problem with a socket as well and interrupt() didn't work. My problem was solved by closing the socket. So in the setStop() method (as proposed above) you would have to call serverSocket.close() (you'd obviously have to make serverSocket a class member or something).
It would help if you had some code which included the code where you plan to change the stopFlag. If it is outside of the thread you could probably use a .interrupt() on the thread followed by a .destroy() on the thread. It is not an ideal solution better probably to try and add a timeout on your server socket see setSoTimeout() method of DatagramSocket in the java api.
I'm unsure where the stop flag comes from but anyway, the answer is interrupt.
Thread t;
ServerSoket serverSoket;
public void startListening() throws Exception {
...
serverSocket = new DatagramSocket(port);
t = new Thread()...;
t.start();
...
}
setStop() {
stopFlag = true;
serverSocket.close()
t.interrupt();
}
Use serverSocket.setSoTimeout(t).

Categories