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();
}
}
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With