I'm having a difficult time getting my head around how to use ThreadRenamingRunnable to rename the worker thread in netty. I am new to netty and using netty 3.9.0-Final.
I want to rename the worker threads..."New I/O worker #X". I'm ok with the name of the boss thread.
This is a basic server which responds to a "ping" with a "pong".
public class NettyPingPong {
public static void main(String[] args) {
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new LineBasedFrameDecoder(255,true,true),
new PongUpstreamHandler(),
new StringEncoder());
}
});
bootstrap.bind(new InetSocketAddress(8899));
out.println("im ready");
}
}
and
public class PongUpstreamHandler extends SimpleChannelUpstreamHandler {
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
String message = new String(buffer.array());
if (message.equalsIgnoreCase("ping")){
e.getChannel().write("pong\n");
out.println("ponged...");
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace();
e.getChannel().close();
out.println("closed...");
}
}
1.5 years old question :( I landed here with the same question, working on Netty 3.5.0 Final. And I resolved with the below code.
I used a thread factory which would also generage meaningful threadNames similar to what Abe has mentioned.
And, I configured ThreadRenamingRunnable not to rename the threads I supply. Using ThreadFactory and setting ThreadNameDeterminer as CURRENT.
ThreadRenamingRunnable.setThreadNameDeterminer(ThreadNameDeterminer.CURRENT);
Netty (3.5.0 atleast) alters the threadName from its original value to a proposed value "New I/O Worker #X". The above code snippet, ensures that it doesn't alter the thread name. The name is determined by the below ThreadFactory.
public class CustomThreadFactory implements ThreadFactory {
private final AtomicInteger threadIdSequence = new AtomicInteger(0);
private String threadNamePrefix = "Netty-Worker-";
public CustomThreadFactory() {
}
public CustomThreadFactory(String namePrefix) {
this.threadNamePrefix = namePrefix;
}
#Override
public Thread newThread(Runnable runnable) {
Thread newThread = new Thread(runnable, threadNamePrefix + threadIdSequence.incrementAndGet());
if (newThread.isDaemon()) {
newThread.setDaemon(false);
}
if (newThread.getPriority() != Thread.NORM_PRIORITY) {
newThread.setPriority(Thread.NORM_PRIORITY);
}
newThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(final Thread thread, final Throwable e) {
System.err.println(thread + " threw exception: " + e.getMessage());
e.printStackTrace();
}
});
return newThread;
}
}
There may be better ways to do this, but this is how i got it to work. Thanks to this blog.
public class NettyPingPong {
public static void main(String[] args) {
final String WORKER_THREADNAME_PREFIX = "worker";
NioWorkerPool workerPool = new NioWorkerPool(Executors.newCachedThreadPool(), 20, new ThreadNameDeterminer() {
#Override
public String determineThreadName(String currentThreadName,String proposedThreadName) throws Exception {
StringBuilder sb = new StringBuilder(WORKER_THREADNAME_PREFIX);
sb.append(currentThreadName.substring(currentThreadName.lastIndexOf('-')));
return sb.toString();
}
});
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
workerPool));
bootstrap.setPipelineFactory(
new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(
new LineBasedFrameDecoder(255, true, true),
new PongUpstreamHandler(),
new StringEncoder());
}
});
bootstrap.bind(new InetSocketAddress(8899));
out.println("im ready");
}
}
You can pass in a ThreadFactory which will name your thread. Take a look at this ThreadFactory I am using to name the server threads. Provided below is the example usage
serverBootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(Executors
.newCachedThreadPool(new NamedThreadFactory(
"TCP-Server-Boss")), Executors
.newCachedThreadPool(new NamedThreadFactory(
"TCP-Server-Worker"))));
Related
I have a driver/main class in file like this. (Basically I'm trying to mix STORM & AKKA). In TenderEventSpout2 class, I am trying to send and receive message to/from an actor.
public class TenderEventSpout2 extends BaseRichSpout {
ActorSystemHandle actorSystemHandle;
ActorSystem _system;
ActorRef eventSpoutActor;
Future<Object> future;
Timeout timeout;
String result;
#Override
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
//String[] message = {"WATCH_DIR"};
timeout = new Timeout(Duration.create(60, "seconds"));
List<Object> messageList = new ArrayList<Object>();
messageList.add("WATCH_DIR");
messageList.add(this.inputDirName);
actorSystemHandle = new ActorSystemHandle();
_system = actorSystemHandle.getActorSystem();
eventSpoutActor = _system.actorOf(Props.create(EventSpoutActor.class));
future = Patterns.ask(eventSpoutActor, messageList, timeout);
}
#Override
public void nextTuple() {
String result = null;
try{
result = (String) Await.result(future, timeout.duration());
}
catch(Exception e){
e.printStackTrace();
}
}
My Actor is:
public class EventSpoutActor extends UntypedActor {
public ConcurrentLinkedQueue<String> eventQueue = new ConcurrentLinkedQueue<>();
Inbox inbox;
#Override
public void onReceive(Object message){// throws IOException {
if (message instanceof List<?>) {
System.out.println(((List<Object>)message).get(0)+"*******************");
if(((List<Object>)message).get(0).equals("WATCH_DIR")){
final List<Object> msg = (List<Object>)message;
Thread fileWatcher = new Thread(new Runnable(){
#Override
public void run() {
System.out.println(msg.get(1)+"*******************");
try {
String result = "Hello";
System.out.println("Before Sending Message *******************");
getSender().tell(result, getSelf());
}
catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
}
});
fileWatcher.setDaemon(true);
fileWatcher.start();
System.out.println("Started file watcher");
}
}
else{
System.out.println("Unhandled !!");
unhandled(message);
}
}
}
I'm able to send message to my EventSpoutActor. But facing problem with receiving messages. Why is that?? I get the following message printed in console:
[EventProcessorActorSystem-akka.actor.default-dispatcher-3]
[akka://EventProcessorActorSystem/deadLetters] Message [java.lang.String]
from Actor[akka://EventProcessorActorSystem/user/$a#-1284357486] to
Actor[akka://EventProcessorActorSystem/deadLetters] was not delivered. [1]
dead letters encountered.
This logging can be turned off or adjusted with configuration settings
'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
So, I found out why the messages were not delivered.
getSender().tell(result, getSelf());
This line which is supposed to send the messages to the sender, lost it's context data, when it is used inside Thread code:
Thread fileWatcher = new Thread(new Runnable(){
#Override
public void run() {
System.out.println(msg.get(1)+"*******************");
try {
String result = "Hello";
System.out.println("Before Sending Message *******************");
getSender().tell(result, getSelf());
When I moved the "tell" code outside the thread, it worked.
I am creating a Netty/JavaFX application and i faced with a following exception when i try to send a picture from client to server.
Exception in thread "nioEventLoopGroup-3-1" java.lang.IllegalStateException: Not on FX application thread; currentThread = nioEventLoopGroup-3-1
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
at javafx.scene.Node.notifyParentsOfInvalidatedCSS(Node.java:8709)
at javafx.scene.Node.requestCssStateTransition(Node.java:8639)
at javafx.scene.Node.pseudoClassStateChanged(Node.java:8680)
at javafx.scene.Node$FocusedProperty.markInvalid(Node.java:7535)
at javafx.scene.Node$FocusedProperty.store(Node.java:7520)
at javafx.scene.Node.setFocused(Node.java:7578)
at javafx.scene.control.TableRow.updateFocus(TableRow.java:305)
at javafx.scene.control.TableRow.lambda$new$58(TableRow.java:106)
at javafx.scene.control.TableRow$$Lambda$197/862831050.invalidated(Unknown Source)
at javafx.beans.WeakInvalidationListener.invalidated(WeakInvalidationListener.java:83)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyObjectWrapper.java:176)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:142)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:145)
at javafx.scene.control.TableView$TableViewFocusModel.setFocusedCell(TableView.java:2981)
at javafx.scene.control.TableView$TableViewFocusModel.focus(TableView.java:3022)
at javafx.scene.control.TableView$TableViewSelectionModel.focus(TableView.java:1941)
at javafx.scene.control.TableView$TableViewSelectionModel.focus(TableView.java:1935)
at javafx.scene.control.TableView$TableViewSelectionModel.focus(TableView.java:1918)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel.clearSelection(TableView.java:2554)
at javafx.scene.control.TableView$TableViewArrayListSelectionModel$3.onChanged(TableView.java:2036)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:183)
at network.ServerHandler.handlerRemoved(ServerHandler.java:53)
at io.netty.channel.DefaultChannelPipeline.callHandlerRemoved0(DefaultChannelPipeline.java:527)
at io.netty.channel.DefaultChannelPipeline.callHandlerRemoved(DefaultChannelPipeline.java:521)
at io.netty.channel.DefaultChannelPipeline.remove0(DefaultChannelPipeline.java:351)
at io.netty.channel.DefaultChannelPipeline.destroyDown(DefaultChannelPipeline.java:798)
at io.netty.channel.DefaultChannelPipeline.destroyUp(DefaultChannelPipeline.java:767)
at io.netty.channel.DefaultChannelPipeline.destroy(DefaultChannelPipeline.java:759)
at io.netty.channel.DefaultChannelPipeline.fireChannelUnregistered(DefaultChannelPipeline.java:743)
at io.netty.channel.AbstractChannel$AbstractUnsafe$6.run(AbstractChannel.java:615)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:745)
This exception thrown when i launch my app as javafx application. When istart it as an console application, the client disconnect from the server but no error or exception shown.
Client handler:
class ClientHandler extends ChannelInboundMessageHandlerAdapter<Object> {
#Override
public void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception {
MessageWrapper message = (MessageWrapper) msg;
System.out.println(message);
switch (message.getHeader()) {
case "IMG":
takeAndSendScreenShot();
default:;
}
}
private void takeAndSendScreenShot() throws IOException {
// try {
// //originalImage = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
//
// } catch (AWTException ex) {
// Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
// }
BufferedImage originalImage = ImageIO.read(new File("c:\\test.jpg"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "jpg", baos);
baos.flush();
byte[] imageInByte = baos.toByteArray();
baos.close();
Client.getChannel().write(new MessageWrapper("IMG", baos));
// Client.getChannel().write(new MessageWrapper("TEST", "TEST"));
}
}
server:
public class Server {
private static final Logger log = Logger.getLogger(Server.class.getName());
private final int port;
public Server(int port) {
this.port = port;
}
public void run() throws InterruptedException {
EventLoopGroup mainGroup = new NioEventLoopGroup();
EventLoopGroup slaveGroup = new NioEventLoopGroup();
try {
ServerBootstrap bootstarp = new ServerBootstrap()
.group(mainGroup, slaveGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ServerInitaizer());
bootstarp.bind(port).sync().channel().closeFuture().sync();
} finally {
mainGroup.shutdownGracefully();
slaveGroup.shutdownGracefully();
}
}
}
Server init:
public class ServerInitaizer extends ChannelInitializer<SocketChannel> {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
// pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.softCachingResolver(ClassLoader.getSystemClassLoader())));
pipeline.addLast("decoder", new ObjectDecoder(ClassResolvers.weakCachingConcurrentResolver(ClassLoader.getSystemClassLoader())));
pipeline.addLast("encoder", new ObjectEncoder());
pipeline.addLast("handler", new ServerHandler());
}
}
server handler:
public class ServerHandler extends SimpleChannelInboundHandler<Object> {
private static final Logger log = Logger.getLogger(Server.class.getName());
private static final ChannelGroup channels = new DefaultChannelGroup(
GlobalEventExecutor.INSTANCE);
private static final ObservableList<Client> clients
= FXCollections.observableArrayList(
(Client c) -> new Observable[]{c.userNameProperty(), c.remoteAddressProperty()});
#Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
log.info(ctx.toString());
Channel incoming = ctx.channel();
channels.add(incoming);
clients.add(new Client(incoming.remoteAddress().toString(), ""));
}
#Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
Channel incoming = null;
log.info(ctx.toString());
try {
incoming = ctx.channel();
for (int i = clients.size() - 1; i > -1; i--) {
if (incoming.remoteAddress().toString().equals(clients.get(i).getRemoteAddress())) {
clients.remove(i);
}
}
} finally {
channels.remove(incoming);
}
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg)
throws Exception {
log.info(msg.toString());
Channel incoming = ctx.channel();
MessageWrapper message = (MessageWrapper) msg;
switch (message.getHeader()) {
case "MSG":
saveMessage(incoming, message.getContent().toString());
case "USER":
setUser(incoming, message.getContent().toString());
default:;
}
}
Message wrapper:
#Data
public class MessageWrapper implements Serializable{
private static final long serialVersionUID = 1L;
String header;
Object content;
public MessageWrapper(String message, Object content) {
this.header = message;
this.content = content;
}
}
Main.java:
public class Main extends Application {
public static void main(String[] args) throws InterruptedException {
launch(args);
//new Server(8000).run();
}
#Override
public void start(Stage stage) throws Exception {
Task<Integer> task = new Task<Integer>() {
#Override
protected Integer call() {
try {
new Server(8000).run();
} catch (Exception e) {
System.out.println(e);
}
return 1;
}
};
Thread th = new Thread(task);
th.setDaemon(true);
System.out.println("Starting server task...");
th.start();
Parent root = FXMLLoader.load(getClass().getResource("/fxml/TablePanel.fxml"));
Scene scene = new Scene(root);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
}
}
If anyone can tell me what is the problem or how can i get more information about this. I would really appraciate.
You have an ObservableList which is used as a model for a JavaFX control, and you're updating that list from a Netty thread. This causes JavaFX to attempt to update the UI from a Netty thread, which is not allowed (all UI operations need to be performed in the application thread). You need to use Platform.runLater() to transfer execution to the application thread.
I'm getting a java.nio.channels.NotYetConnectedException in the following code because I'm trying to write to a channel that is not yet open.
Essentially what I have is a channel pool in which I grab a channel to write to if one is free, and I create a new channel if one is not available. My problem is that when I create a new channel, the channel is not ready for writing when I call connect, and I don't want to wait for the connection to open before returning because I don't want to block the thread. What's the best way to do this? Also, is my logic for retrieving/returning channels valid? See code below.
I have a simple connection pool like the following:
private static class ChannelPool {
private final ClientBootstrap cb;
private Set<Channel> activeChannels = new HashSet<Channel>();
private Deque<Channel> freeChannels = new ArrayDeque<Channel>();
public ChannelPool() {
ChannelFactory clientFactory =
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
cb = new ClientBootstrap(clientFactory);
cb.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() {
return Channels.pipeline(
new HttpRequestEncoder(),
new HttpResponseDecoder(),
new ResponseHandler());
}
});
}
private Channel newChannel() {
ChannelFuture cf;
synchronized (cb) {
cf = cb.connect(new InetSocketAddress("localhost", 18080));
}
final Channel ret = cf.getChannel();
ret.getCloseFuture().addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture arg0) throws Exception {
System.out.println("channel closed?");
synchronized (activeChannels) {
activeChannels.remove(ret);
}
}
});
synchronized (activeChannels) {
activeChannels.add(ret);
}
System.out.println("returning new channel");
return ret;
}
public Channel getFreeChannel() {
synchronized (freeChannels) {
while (!freeChannels.isEmpty()) {
Channel ch = freeChannels.pollFirst();
if (ch.isOpen()) {
return ch;
}
}
}
return newChannel();
}
public void returnChannel(Channel ch) {
synchronized (freeChannels) {
freeChannels.addLast(ch);
}
}
}
I'm trying to use this inside a handler as follows:
private static class RequestHandler extends SimpleChannelHandler {
#Override
public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) {
final HttpRequest request = (HttpRequest) e.getMessage();
Channel proxyChannel = pool.getFreeChannel();
proxyToClient.put(proxyChannel, e.getChannel());
proxyChannel.write(request);
}
}
Instead of adding the new channel to activeChannels immediately after bootstrap.connect(..), you have to add a listener to the ChannelFuture which was returned by bootstrap.connect(..), and add the channel to activeChannels in the added listener. That way, getFreeChannel() will never get the channel that is not connected yet.
Because it is likely that activeChannels is empty even if you called newChannel() (newChannel() will return even before connection is established), you have to decide what to do in such a case. If I were you, I would change the return type of getFreeChannel() from Channel to ChannelFuture so that the caller gets notified when the free channel is ready.
I just can't realize why my read time out is not working. All I want to do is just to wait
for 10 seconds for some thread to put message to BlockedQueue<String> and on timeout return some kind of response on client.
public class NioAsynChatPipelineFactory implements ChannelPipelineFactory {
private static Timer timer = new HashedWheelTimer();
private final ChannelHandler timeoutHandler = new ReadTimeoutHandler(timer, 10);
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("decoder", new HttpRequestDecoder());
pipeline.addLast("encoder", new HttpResponseEncoder());
pipeline.addLast("handler", new NioAsynChatHandler());
pipeline.addLast("timeout", this.timeoutHandler);
return pipeline;
}
}
Now my handler looks like this.
public class NioAsynChatHandler extends SimpleChannelUpstreamHandler{
#Override
public void handleUpstream(
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
super.handleUpstream(ctx, e);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
System.out.println("Exception");
\\writing some kind of response and closing channel.
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
Thread thread = new Thread(new ConsmerTask(e.getChannel()));
thread.start();
}
and inside ConsumerTask I'm just waiting for BlockingQueue to get response
public class ConsumerTask implements Runnable{
private Channel channel;
public ConsumerTask(Channel channel){
this.channel = channel;
}
#Override
public void run() {
try{
while(true){
String message = queue.take();
}
} catch(InterruptedException ex){
Thread.currentThread.interrupt();
} finally{
//write something to channel and close it
}
}
My problem is that I don't see that any excpetion occurs on time out.
What am I doing wrong?
Update:
public static final BlockingQueue<String> blockingQueue = new LinkedBlockingQueue<String>();
Actually my question is more generic, How to close channel on timeout while it is waiting for something in external thread?
Update 2:
Another question: due to the fact that I'm running external thread in Cha would it be better to use OrderedMemoryAwareThreadPoolExecutor in pipeline? Will it increase performance.
It's basically because you put the ReadTimeoutHandler in the wrong position. Please put it in the first position of the pipeline (i.e. before all handlers).
This is my first time using Netty and I'm having trouble making a simple echo server! I looked at docs and it says to use the string encoder and decoder, which I am not using properly apparently. For the framedecoder, I'd like to use the header messages with one byte length, but that doesn't seem to be working either due to the string issue. I assume my implementation of the PipelineFactory is messed up.
Bonus Question:
Because I'm stupid and ambitious, I tried implementing a timeout/heartbeat handler. That didn't work either.
Here are the console output and java code:
Console:
>>telnet localhost 6969
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
>>3
Connection closed by foreign host.
Java Console:
Starting server on 6969
channelConnected
channelDisconnected
java.lang.IllegalArgumentException: unsupported message type: class java.lang.String
at org.jboss.netty.channel.socket.nio.SocketSendBufferPool.acquire(SocketSendBufferPool.java:51)
at org.jboss.netty.channel.socket.nio.NioWorker.write0(NioWorker.java:455)
...
Server.java
public class Server {
public static void main(String[] args) throws Exception {
ChannelFactory factory =
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
ServerBootstrap bootstrap = new ServerBootstrap(factory);
Timer timer = new HashedWheelTimer();
bootstrap.setPipelineFactory(new MyPipelineFactory(timer) {
public ChannelPipeline getPipeline() {
return Channels.pipeline(new ServerHandler());
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.bind(new InetSocketAddress(6969));
System.out.println("Starting server on 6969");
}
}
ServerHandler.java
public class ServerHandler extends SimpleChannelHandler {
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){
Channel ch = e.getChannel();
System.out.println("channelConnected");
}
#Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e){
Channel ch = e.getChannel();
System.out.println("channelDisconnected");
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
String msg = (String) e.getMessage();
e.getChannel().write("Did you say '" + msg + "'?\n");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
e.getCause().printStackTrace();
Channel ch = e.getChannel();
ch.close();
}
}
MyPipelineFactory.java
public class MyPipelineFactory implements ChannelPipelineFactory {
private final Timer timer;
private static ChannelHandler idleStateHandler;
public MyPipelineFactory(Timer t) {
this.timer = t;
//this.idleStateHandler = new IdleStateHandler(timer, 5, 20, 0); // timer must be shared
}
public ChannelPipeline getPipeline() {
// create default pipeline from static method
ChannelPipeline pipeline = Channels.pipeline();
// Decoders
int maxFrameLength = 1024;
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(maxFrameLength, Delimiters.lineDelimiter()));
//pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(maxFrameLength,0,1)); // get header from message
pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
// Encoders
pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));
// Idle state handling- heartbeat
//pipeline.addLast("idleStateHandler", idleStateHandler);
return pipeline;
}
}
Bonus, because I'm stupid and want to get in over my head...
HeartbeatHandler.java
public class HeartbeatHandler extends IdleStateAwareChannelHandler {
#Override
public void channelIdle(ChannelHandlerContext ctx, IdleStateEvent e) {
if (e.getState() == IdleState.READER_IDLE) {
System.out.println("Reader idle, closing channel");
e.getChannel().close();
}
else if (e.getState() == IdleState.WRITER_IDLE) {
System.out.println("Writer idle, sending heartbeat");
e.getChannel().write("heartbeat"); //
}
}
}
It's because you mess up the ChannelPipeline.
You use:
bootstrap.setPipelineFactory(new MyPipelineFactory(timer) {
public ChannelPipeline getPipeline() {
return Channels.pipeline(new ServerHandler());
}
});
What you would need todo is modify the MyPipelineFactory class and add your ServerHandler in there. Then just set it like:
bootstrap.setPipelineFactory(new MyPipelineFactory(timer));
Then everything should work. Even your timeout stuff ;)