1

我正在实现 Jetty 的 WebSocket.OnTextMessage。当我在 onMessage(String) 中收到消息时,我可以使用之前从 onOpen(Connection) 获取的 Connection 对象进行回复,并且客户端会正确接收它。

但是,当我想使用 connection.sendMessage(String) 从服务器推送消息(即没有来自客户端的初始消息)时,客户端不会收到它。似乎消息正在被缓冲,但我找不到任何方法来刷新它。

有谁知道如何解决这个问题?也许我做的是不正确的。这就是我所做的

public void onOpen(final Connection connection) {
    this.connection = connection;
}

然后在另一个事件

public void onReceive(BytesXMLMessage bytesXMLMessage) {
    byte[] data = ((BytesMessageImpl) bytesXMLMessage).getData();
    String msgToClient = new String(data);
    this.connection.sendMessage(msgToClient);
    System.out.println("onReceive:" + msgToClient);
}

但是客户端从未收到该消息

更新:找到模式,无论是大写还是小写,只要包含HTTP方法关键字(例如GET,POST,PUT,HEAD等),消息将永远不会发送给客户端。

有没有办法缓解这个问题?

更新:这是可以模拟问题的非常简化的 WebSocketServlet 实现

package com.test.websocket;

import org.eclipse.jetty.websocket.WebSocket;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class WebSocketServlet extends org.eclipse.jetty.websocket.WebSocketServlet {
    @Override
    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
        return new WebSocket.OnTextMessage() {
            private Connection connection;
            @Override
            public void onMessage(String data) {
                try {
                    connection.sendMessage("Echo: " + data);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onOpen(Connection connection) {
                this.connection = connection;
            }

            @Override
            public void onClose(int closeCode, String message) {
                connection.close();
            }
        };
    }
}

这是 web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <servlet>
        <servlet-name>EchoWebSocket</servlet-name>
        <servlet-class>com.test.websocket.WebSocketServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EchoWebSocket</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
4

3 回答 3

2

找到了无法发送 HTTP 方法关键字的根本原因。它是由在开发机器上运行的 Antivirus Kaspersky 引起的,它在网络层拦截所有 HTTP 方法关键字,并且它必须在适当的标准 HTTP 协议中工作。也许它还不支持 websocket 协议。

感谢 @jesse mcconnell 帮助创建单元测试。

于 2012-09-25T16:16:02.857 回答
0

[编辑]

我无法通过单元测试验证这一点,我让客户端发送“GET”消息,然后服务器端返回相同的字符串,客户端接收它。如果您有更多关于它的信息,请在 RT/Jetty 项目下的 bugs.eclipse.org 上打开一个重现方式的问题(如果您愿意)。

在这一点上,如果您可以发布一些代码来查看或可能有帮助的东西,我倾向于您的实施问题。

这是您描述的新测试用例: http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/commit/?id= 494f7e48fcc20c51066cd91a6dac1d738cacb54e

于 2012-09-25T12:32:38.807 回答
0

websocket 协议旨在尽量避免看起来像 HTTP 流量。具体来说,它将随机掩码应用于从客户端发送到服务器的所有帧的有效负载,因此 websocket 消息不太可能看起来像 HTTP 请求。

然而,该协议不会屏蔽从服务器发送到客户端的有效负载,因为当时的想法是,可能存在可以利用该方向的流量来利用的攻击向量。

我想我们没有考虑到像您的防火墙这样的中介在他们寻找和阻止的内容方面可能有点过于严格。我想不出他们为什么要阻止这样的流量,因为我可以想象它也会阻止像 XMPP 消息这样的文本,比如“不要忘记拿牛奶!”。但它确实......所以唯一真正的选择是你:

  1. 自己编码有效载荷内容并在客户端解码。
  2. 关闭防火墙(或解调)
  3. 修好防火墙。
于 2012-09-28T00:21:21.690 回答