无法通过tomcat中的websocket发送二进制消息,但可以在glassfish中使用。使用IllegalArgumentException在tomcat中失败

时间:2015-01-22 04:13:25

标签: java websocket glassfish tomcat8

我正在尝试通过websocket发送使用协议缓冲区编码的二进制消息。我能够使用Glassfish 4.0成功发送。但是相同的代码在tomcat 8中失败,但下面有例外。

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)

以下是用于处理二进制消息并将其发回的java实现

 @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("jdoe@example.com")
                    .addPhone(
                      Person.PhoneNumber.newBuilder()
                        .setNumber("555-4321")
                        .setType(Person.PhoneType.HOME))
                    .build();
        Person keith =
                Person.newBuilder().setId(1234).setName("John Doe").setEmail("jdoe@example.com").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();
        }
    }

1 个答案:

答案 0 :(得分:5)

看起来您需要检查tomcat服务器配置的缓冲区大小。 二进制消息的默认缓冲区大小为8192字节。见WebSocket Howto

incomingAddressBook.toByteArray().length的价值是什么?

在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>

另外,请使用以下。,

ByteBuffer buffer = ByteBuffer.allocate(incomingAddressBook.toByteArray().length).put(incomingAddressBook.toByteArray());
buffer.flip(); //before sending message
session.getBasicRemote().sendBinary(buffer);