简体   繁体   English

如何在码头容器中设置JSR356 WebSockets

[英]How do I setup JSR356 websockets in a jetty container

I see lots of tutorials about how to set up JSR356 websockets with an embedded web server of some sort. 我看到很多关于如何使用某种嵌入式Web服务器设置JSR356 Web套接字的教程。

But I want to add some websockets to an existing WAR deployed to a stand alone jetty installation, jetty jetty-9.2.3.v20140905, and I can find very little information on this. 但是我想在部署到独立码头设备jetty jetty-9.2.3.v20140905的现有WAR中添加一些Websocket,在此方面我几乎找不到任何信息。 I can't figure out what is preventing it from working. 我不知道是什么阻止了它的工作。 As I understand it, the annotated server endpoints should be automatically handled by jetty. 据我了解,带注释的服务器端点应该由码头自动处理。

ServerEndpoint: ServerEndpoint:

    @ServerEndpoint(value = "/myendpoint")
public class MyServerEndpoint {     
    private Logger logger = Logger.getLogger(this.getClass().getName());     

    @OnOpen 
    public void onOpen(Session s) {
        logger.info("Server Connected ... " + s.getId());
        s.getAsyncRemote().sendText("You are connected to the websocket server");   
    }        

    @OnMessage  
    public void onMessage(String message, Session session) {

        // Sent the message back to all connected users             
        logger.info("Server Session " + session + " Received string message " + message);

        for(Session s: session.getOpenSessions()) {     
            if (s.isOpen()) { 
                s.getAsyncRemote().sendText(message + " server response");
            }       
        }   
    }        

    @OnClose    
    public void onClose(Session session, CloseReason reason) {
        logger.info("Server Session " + session + " closed for reason " + reason);
    }   
}

ClientEndpoint: ClientEndpoint:

    @ClientEndpoint
public class MyClientEndpoint {     
    private Logger logger = Logger.getLogger(this.getClass().getName());     

    @OnOpen 
    public void onOpen(Session s) {
        logger.info("Client Connected ... " + s.getId());
        s.getAsyncRemote().sendText("hello from the client!");  
    }        

    @OnMessage  
    public void onMessage(String message, Session session) {

        logger.info("Client Session " + session + " Received string message " + message);       

    }        

    @OnClose    
    public void onClose(Session session, CloseReason reason) {
        logger.info("Client Session " + session + " closed for reason " + reason);
    }   
}

Here is the code (run inside some existing method) to connect the client to the server 这是将客户端连接到服务器的代码(在某些现有方法中运行)

    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
    String uri = "ws://localhost:8080/myWar/myendpoint"; 
    container.connectToServer(MyClientEndpoint.class, URI.create(uri));

Yet spinning up jetty gives an error on the connectToServer line 但是旋转码头会在connectToServer线上产生错误

2014-10-30 12:26:58.658:WARN:oeja.ServletContainerInitializersStarter:main: 
org.eclipse.jetty.websocket.api.InvalidWebSocketException: Unable to instantiate websocket: class java.lang.Class
at   org.eclipse.jetty.websocket.jsr356.ClientContainer.newClientEndpointInstance(ClientContainer.java:311)
    at org.eclipse.jetty.websocket.jsr356.ClientContainer.connectToServer(ClientContainer.java:172)

All I can think is that the URI is incorrect. 我只能认为URI不正确。 If jetty is running on 8080 and my .war is named myWar, and my end point is named myendpoint...is that not the correct URI? 如果jetty在8080上运行,而我的.war被命名为myWar,而我的端点被命名为myendpoint ...那不是正确的URI吗?

Is there some additional step that must be done to 'activate' the server endpoint to listen for connections? 是否需要执行一些其他步骤来“激活”服务器端点以侦听连接? I must be missing something obvious. 我一定想念一些明显的东西。

Strangely, your error message. 奇怪的是,您的错误消息。

org.eclipse.jetty.websocket.api.InvalidWebSocketException: 
  Unable to instantiate websocket: class java.lang.Class

Means that the websocket implementation was handed a raw java.lang.Class to instantiate. 意味着将websocket实现传递给原始java.lang.Class进行实例化。 That's not going to work. 那是行不通的。

It also means no attempt was made to connect, as the WebSocket class itself was so bad that a connect was impossible. 这也意味着没有尝试进行连接,因为WebSocket类本身很糟糕,无法进行连接。

Here's a short (valid and working) example showing its use. 这是一个简短(有效且有效)的示例,展示了其用法。

package jetty.jsr356;

import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CountDownLatch;

import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

@ClientEndpoint
public class TestClientAnnotatedClass
{
    private static CountDownLatch closeLatch = new CountDownLatch(1);

    @OnOpen
    public void onOpen(Session session)
    {
        System.out.println("@OnOpen - " + session);
        try
        {
            session.getBasicRemote().sendText("Rock it with Java WebSocket");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @OnMessage
    public void onMessage(Session session, String msg)
    {
        System.out.println("@OnMessage - ["+msg+"]");
        try
        {
            session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE,"Thanks"));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(CloseReason close)
    {
        System.out.println("@OnClose - " + close);
        closeLatch.countDown();
    }

    public static void main(String[] args)
    {
        try
        {
            WebSocketContainer ws = ContainerProvider.getWebSocketContainer();

            ws.connectToServer(TestClientAnnotatedClass.class,new URI("ws://echo.websocket.org/?encoding=text"));
            closeLatch.await();
        }
        catch (Throwable t)
        {
            t.printStackTrace();
        }
    }
}

You'll see output similar to this 您将看到类似于此的输出

2014-10-30 11:34:19.197:INFO::main: Logging initialized @71ms
@OnOpen - WebSocketSession[websocket=JsrAnnotatedEventDriver[websocket=jetty.jsr356.TestClientAnnotatedClass@5cca5f2c],behavior=CLIENT,connection=WebSocketClientConnection@6a2e714b{IDLE}{f=Flusher[queueSize=0,aggregateSize=0,failure=null],g=Generator[CLIENT,validating],p=Parser@55465b1f[ExtensionStack,s=START,c=0,len=0,f=null,p=WebSocketPolicy@7e087bf5[behavior=CLIENT,maxTextMessageSize=65536,maxTextMessageBufferSize=32768,maxBinaryMessageSize=65536,maxBinaryMessageBufferSize=32768,asyncWriteTimeout=60000,idleTimeout=300000,inputBufferSize=4096]]},remote=WebSocketRemoteEndpoint@5f025277[batching=true],incoming=JsrAnnotatedEventDriver[websocket=jetty.jsr356.TestClientAnnotatedClass@5cca5f2c],outgoing=ExtensionStack[queueSize=0,extensions=[],incoming=org.eclipse.jetty.websocket.jsr356.JsrSession,outgoing=org.eclipse.jetty.websocket.client.io.WebSocketClientConnection]]
@OnMessage - [Rock it with Java WebSocket]
@OnClose - CloseReason[1000,Thanks]

Jetty creates instances of annotated client endpoints using reflection (see /jetty/websocket/jsr356/ClientContainer#newClientEndpointInstance() ) but Java is unable to instantiate a non-static inner class that way . Jetty使用反射创建带注释的客户端端点的实例(请参见/ jetty / websocket / jsr356 / ClientContainer#newClientEndpointInstance() ),但是Java无法以这种方式实例化非静态内部类 The actual cause exception is something like java.lang.NoSuchMethodException: <pkg>.OuterClass$InnerClass.<init>() but it is swallowed. 实际的原因异常类似于java.lang.NoSuchMethodException: <pkg>.OuterClass$InnerClass.<init>()但已被吞下。

Solution: annotated endpoint classes should be not nested or nested static (inner) classes. 解决方案:带注释的终结点类不应是嵌套的或嵌套的静态(内部)类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM