Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to send binary message through websocket in tomcat, but works in glassfish. Fails in tomcat with IllegalArgumentException

I am trying to send binary message encoded using protocol buffers through websocket. I am able to successfully send using Glassfish 4.0. But the same code fails in tomcat 8 with exception below.

java.lang.IllegalArgumentException
at java.nio.Buffer.limit(Buffer.java:267)
at org.apache.tomcat.websocket.PerMessageDeflate.sendMessagePart(PerMessageDeflate.java:368)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessage(WsRemoteEndpointImplBase.java:297)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:270)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.sendBytes(WsRemoteEndpointImplBase.java:132)
at org.apache.tomcat.websocket.WsRemoteEndpointBasic.sendBinary(WsRemoteEndpointBasic.java:43)
at com.trsim.sim.endpoint.Whiteboard.broadcastSnapshot(Whiteboard.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:80)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageBinary(WsFrameBase.java:586)
at org.apache.tomcat.websocket.WsFrameBase.processDataBinary(WsFrameBase.java:543)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:295)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:194)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:654)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)

Below is my java implementation for handling a binary message and send it back

 @OnMessage
        public void broadcastSnapshot(ByteBuffer data, Session session) throws IOException {
            //I am able to parse the incoming binary header data
            Header incomingHeader = Header.parseFrom(data.array());
            Header header = Header.newBuilder().setCallback("2").setDecodeusing("MyClasstodecode").build();
            //I am able to parse the incoming data
            AddressBook incomingAddressBook = AddressBook.parseFrom(data.array());


        //Creating Ouput messages
        Person john =
                  Person.newBuilder()
                    .setId(1234)
                    .setName("John Doe")
                    .setEmail("[email protected]")
                    .addPhone(
                      Person.PhoneNumber.newBuilder()
                        .setNumber("555-4321")
                        .setType(Person.PhoneType.HOME))
                    .build();
        Person keith =
                Person.newBuilder().setId(1234).setName("John Doe").setEmail("[email protected]").addPhone(Person.PhoneNumber.newBuilder().setNumber("555-4321").setType(Person.PhoneType.HOME)).build();
        AddressBook.Builder addressBook = AddressBook.newBuilder();
        addressBook.addPerson(john);
        addressBook.addPerson(keith);


        //Converting output message to byte array using Protocol buffers
        byte[] headerArray = header.toByteArray();
        byte[] byteBuffer = addressBook.build().toByteArray();


        ByteBuffer outputBuffer = ByteBuffer.allocate(byteBuffer.length + headerArray.length );
        outputBuffer.put(headerArray,0,headerArray.length);
        outputBuffer.put(byteBuffer,0,byteBuffer.length);

        try{
            //Send the received message first -- fails in tomcat but works in glassfish 4
            ByteBuffer buffer = ByteBuffer.allocate(incomingAddressBook.toByteArray().length).put(incomingAddressBook.toByteArray());
            session.getBasicRemote().sendBinary(buffer);

            //Send the response -- fails in tomcat.. But works in glassfish 4
            session.getBasicRemote().sendBinary(outputBuffer);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
like image 975
anandaravindan Avatar asked Jan 22 '15 04:01

anandaravindan


1 Answers

Looks like you need to check the buffer size of tomcat server configuration. The default buffer size for binary messages is 8192 bytes. See WebSocket Howto

What is the value of incomingAddressBook.toByteArray().length ?

Try the below in your web.xml.,

<context-param>
     <param-name>org.apache.tomcat.websocket.textBufferSize</param-name>
     <param-value>32768</param-value>
</context-param>
<context-param>
     <param-name>org.apache.tomcat.websocket.binaryBufferSize</param-name>
     <param-value>32768</param-value>
</context-param>

Also, use the below.,

ByteBuffer buffer = ByteBuffer.allocate(incomingAddressBook.toByteArray().length).put(incomingAddressBook.toByteArray());
buffer.flip(); //before sending message
session.getBasicRemote().sendBinary(buffer);
like image 84
Senthil Arumugam SP Avatar answered Oct 29 '22 18:10

Senthil Arumugam SP