Harry
Harry

Reputation: 4773

Binding text message with websocket using Netty in browser

I am trying to implement websockets using Netty. I tried DiscardServer example and it works fine if I just run it using Telnet like

  Telnet localhost 8090.

So whatever the message I put in terminal window it returns me back. But now I want to implement same in browser like if I put some text message in a text area then it should display that text message on browser.

I can start the websocket server using the following code

    ChannelFactory factory = new NioServerSocketChannelFactory(
            Executors.newCachedThreadPool(),
            Executors.newCachedThreadPool());

    ServerBootstrap bootstrap = new ServerBootstrap(factory);

    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
        public ChannelPipeline getPipeline() {
            return Channels.pipeline(new DiscardServerHandler());
        }
    });

    bootstrap.setOption("child.tcpNoDelay", true);
    bootstrap.setOption("child.keepAlive", true);

    bootstrap.bind(new InetSocketAddress(8090));

but how can I bind my text message in my text area with the websocket server

----Updated----

I have created MyServerHandler class

   public class MyServerHandler extends SimpleChannelUpstreamHandler {

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    Object msg = e.getMessage();        
    //msg.getClass();
    if (msg instanceof HttpRequest) {
                    //handleHttpRequest(ctx, (HttpRequest) msg);
        ctx.getChannel().write(msg);
    } else if (msg instanceof WebSocketFrame) {
        //handleWebSocketFrame(ctx, (WebSocketFrame) msg);
    }

}
  }

Its calling messageReceived Method but not going to any of if condition.

I wrote WebSocketServerPipelineFactory class also

   public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {

@Override
    public ChannelPipeline getPipeline() throws Exception {
        // Create a default pipeline implementation.
        ChannelPipeline pipeline = pipeline();
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("handler", new MyServerHandler());
        return pipeline;
    }
    }

I thing its not calling method of this class also.

In jsp file I have written

   <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"  type="text/javascript"></script>
   <script>
   var MESSAGE_HANDSHAKE = "handshake";
   var MESSAGE_OPPONENT_UPDATE = "response";
   var MESSAGE_TURN_INDICATOR = "turn";
   var MESSAGE_GAME_OVER = "game_over";
   var WEBSOCKET_URL = "ws://localhost:8090";
   $(document).ready(function() {
   ws = new WebSocket(WEBSOCKET_URL);

   ws.onopen = function(event) { 
 alert("test");
 $('#status').text("Waiting...."); 
  };

   ws.onmessage = function(event) {
    var message = jQuery.parseJSON(event.data);

    alert(message.type);
   }

   }); 

<body>
 <p id="status">&nbsp;</p>
</body>

Its not going to any of jquery methods. Am I still missing something?

Also, If I write

  ws.send("Test Message");

it throws following java script error

 Uncaught Error: INVALID_STATE_ERR: DOM Exception 11 login.htm:33
 (anonymous function) login.htm:33
 f.extend._Deferred.e.resolveWith jquery.min.js:2
 e.extend.ready jquery.min.js:2
 c.addEventListener.C

If I use

   var WEBSOCKET_URL = "wss://echo.websocket.org/";

Then it works so is this that I am not able to connect to my server ?

I am using eclipse to run this code. I am running my jsp code using Apache Tomcat and running websocket server by running WebsocketServer.class as java application. Is that make any difference?

--- Updated---

I wrote the following method in MyServerHandler class and getting the error in my browser

 Error during WebSocket handshake: 'Sec-WebSocket-Accept' header is missing 

MySeverHandler.java

  private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req)
        throws Exception {

    // Allow only GET methods.
    if (req.getMethod() != HttpMethod.GET) {
    //  sendHttpResponse(ctx, req, new DefaultHttpResponse(
        //      HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));
        return;
    }

    // Serve the WebSocket handshake request.
    if (req.getUri().equals(WEBSOCKET_PATH)
            && Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
            && WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {

        // Create the WebSocket handshake response.
        HttpResponse res = new DefaultHttpResponse(
                HTTP_1_1,
                new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
        res.addHeader(Names.UPGRADE, WEBSOCKET);
        res.addHeader(CONNECTION, Values.UPGRADE);


        // Upgrade the connection and send the handshake response.
        ChannelPipeline p = ctx.getChannel().getPipeline();
        p.remove("aggregator");
        p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder());

        // Write handshake response to the channel
        ctx.getChannel().write(res);

        // Upgrade encoder to WebSocketFrameEncoder
        p.replace("encoder", "wsencoder", new WebSocketFrameEncoder());

        // Initialize the game. Assign players to a game and assign them a letter (X or O)
        ///initGame(ctx);

        return;
    }

    // Send an error page otherwise.
    sendHttpResponse(ctx, req, new DefaultHttpResponse(
            HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));
}

Upvotes: 1

Views: 1468

Answers (1)

Abe
Abe

Reputation: 9031

Netty uses chain of responsibility design pattern, so whenever you need to use a protocol you need to create appropriate decoders/encoders in your pipeline. For websocket here is an example pipeline.

public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
    public ChannelPipeline getPipeline() throws Exception {
            // Create a default pipeline implementation.
            ChannelPipeline pipeline = pipeline();
            pipeline.addLast("decoder", new HttpRequestDecoder());
            pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
            pipeline.addLast("encoder", new HttpResponseEncoder());
            pipeline.addLast("handler", new YourBusinessHandler());
            return pipeline;
    }

}

You can write any business logic in your buisness handler. In this case you would just be echoing back what you received so it would be something like channel.write(incomingMessage); in this handler.

Take a look at this tic-tac-toe game for more information. Also there are many links information in github on how to do this.

Upvotes: 1

Related Questions