เซิร์ฟเวอร์ Tyrus สามารถใช้จุดสิ้นสุดคลาสภายในได้หรือไม่

ฉันประสบปัญหาในการทำให้เซิร์ฟเวอร์ Tyrus websocket แบบสแตนด์อโลนที่เรียบง่ายอย่างยิ่งทำงานได้ ฉันได้ดำเนินการนี้ภายใต้สถานการณ์ที่เฉพาะเจาะจงซึ่งไม่สมเหตุสมผลสำหรับฉัน

กรณีที่ทำงานอย่างถูกต้องคือที่ฉันกำหนดคลาสจุดสิ้นสุดเซิร์ฟเวอร์ระดับบนสุด (ในไฟล์ของตัวเอง) และใส่คำอธิบายประกอบด้วย @ServerEndpoint คลาสนี้รวมวิธีการที่มีคำอธิบายประกอบด้วย @OnOpen, @OnMessage และ @OnClose ซึ่งเป็นสิ่งทั่วไปทั้งหมด ฉันส่งคลาสนี้ไปยังตัวสร้างเซิร์ฟเวอร์ ไคลเอนต์ธรรมดาของฉันสามารถเชื่อมต่อกับเซิร์ฟเวอร์นี้ และส่งข้อความที่เซิร์ฟเวอร์ได้รับได้สำเร็จ

ปัญหาเกิดขึ้นเมื่อฉันเปลี่ยนคลาสจุดสิ้นสุดเซิร์ฟเวอร์ระดับบนสุดให้เป็นคลาสภายในของคลาสที่กำลังเตรียมใช้งานเซิร์ฟเวอร์ (นี่เป็นการเปลี่ยนแปลงเดียวที่ฉันทำ) ในกรณีนี้ ลูกค้าของฉันสามารถเชื่อมต่อได้และเรียกใช้เมธอด @OnOpen ของลูกค้า แต่เซิร์ฟเวอร์ไม่สร้างอินสแตนซ์จุดสิ้นสุดของเซิร์ฟเวอร์ และด้วยเหตุนี้ จึงไม่มีการเรียกใช้เมธอด @OnOpen แน่นอนว่าการรับข้อความจากเซิร์ฟเวอร์ไม่เกิดขึ้น

มีข้อกำหนดใน Tyrus ที่ว่าคลาสจุดสิ้นสุดของเซิร์ฟเวอร์ที่มีคำอธิบายประกอบไม่สามารถเป็นคลาสภายในได้หรือไม่ ถ้าไม่ มีสิทธิ์เฉพาะสำหรับคลาสจุดสิ้นสุดของเซิร์ฟเวอร์ (ทุกอย่างถูกเปิดเผยต่อสาธารณะโดยพยายามทำให้สิ่งนี้ทำงานได้โดยไม่มีโชค) ฉันใช้ Tyrus 1.9 กับ JDK 1.7 บน Mac, OSX 1.9.5

เซิร์ฟเวอร์แบบธรรมดา (รวมถึงและกำหนดค่าให้ใช้จุดสิ้นสุดเซิร์ฟเวอร์ภายในที่ล้มเหลว):

package tyrus.example;

import java.util.concurrent.TimeUnit;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.glassfish.tyrus.server.Server;

public class SimpleServer
{
    private static final String HOST_ADDR = "localhost";
    private static final int HOST_PORT = 8025;

    public static void main(String[] args) {
        Server websocketServer = new Server(HOST_ADDR, HOST_PORT, "/ws", null, InnerSimpleServerEndpoint.class);

        try {
            websocketServer.start();
            Thread.sleep(TimeUnit.MINUTES.toMillis(5));
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        websocketServer.stop();

        System.out.println("Done.");
    }

    @ServerEndpoint("/myapp")
    public class InnerSimpleServerEndpoint {
        @OnOpen
        public void onOpen(Session session) {
            System.out.println("Connection received for "+session.getRequestURI());
        }

        @OnMessage
        public void onMessage(String message, Session session) {
            System.out.println("Message received: "+message);
        }

        @OnClose
        public void onClose(Session session, CloseReason closeReason) {
            System.out.println("Session closed, reason: "+closeReason);
        }
    }
}

ลูกค้าธรรมดา:

package tyrus.example;

import java.io.IOException;
import java.net.URI;

import javax.websocket.ClientEndpointConfig;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;

import org.glassfish.tyrus.client.ClientManager;

public class SimpleClient
{
    private static final String DEF_WS_URL = "ws://localhost:8025/ws/myapp";

    public static void main(String[] args) {
        ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
        ClientManager client = ClientManager.createClient();

        try {
            client.connectToServer(new ClientEndpoint(), cec, new URI(DEF_WS_URL));
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("Done.");
    }

    private static class ClientEndpoint extends Endpoint {
        @Override
        public void onOpen(Session session, EndpointConfig config) {
            System.out.println("ClientEndpoint: server session opened: "+session);

            session.addMessageHandler(new MessageHandler.Whole<String>() {
                @Override
                public void onMessage(String message) {
                    System.out.println("ClientEndpoint: received message: "+message);
                }
            });

            try {
                session.getBasicRemote().sendText("Hello server!");
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

และสุดท้ายคือจุดสิ้นสุดเซิร์ฟเวอร์ที่ไม่ใช่คลาสภายในที่ทำงานเมื่อเซิร์ฟเวอร์ใช้งาน:

package tyrus.example;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/myapp")
public class SimpleServerEndpoint {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connection received for "+session.getRequestURI());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Message received: "+message);
    }

    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println("Session closed, reason: "+closeReason);
    }
}

person Bill Balloni    schedule 09.03.2015    source แหล่งที่มา


คำตอบ (3)


บนเซิร์ฟเวอร์ จุดสิ้นสุดสามารถเป็นคลาสภายในได้ แต่ก็ต้องเป็นแบบคงที่ด้วย แม้ว่าโค้ดจะทำงานและให้บริการด้วยเหตุผลบางประการ ฉันสามารถทำให้มันทำงานได้ก็ต่อเมื่อจุดสิ้นสุดของเซิร์ฟเวอร์เป็นแบบคงที่เช่นกัน เช่น: เปลี่ยนเพื่อเพิ่มสแตติกในรหัสเซิร์ฟเวอร์:

@ServerEndpoint("/myapp") public static class InnerSimpleServerEndpoint { }

คุณอาจต้องการเพิ่ม

@OnError public void onError(Session session, Throwable throwable) { //... }

person jazeee    schedule 09.04.2016
comment
ขอบคุณ ฉันประสบปัญหาเดียวกัน ชั้นเรียนต้องเป็นทั้งแบบสาธารณะและแบบคงที่ - person Samuel; 29.08.2017

จุดสิ้นสุดสามารถเป็นคลาสภายในได้ แต่จะต้องเป็นแบบทันที - คลาส ClientEndpoint ในตัวอย่างที่ล้มเหลวของคุณคือ private ดังนั้น Tyrus จึงไม่สามารถสร้างอินสแตนซ์ได้

เปลี่ยนเป็นสาธารณะและควรจะทำงานได้ตามที่คาดไว้

person Pavel Bucek    schedule 09.03.2015
comment
พาเวลปัญหาอยู่ที่เซิร์ฟเวอร์ ไม่ใช่ไคลเอนต์ เนื่องจากโค้ดไคลเอ็นต์ของฉันสร้างอินสแตนซ์ปลายทาง ไคลเอ็นต์จึงทำงานได้ดี แต่เซิร์ฟเวอร์ ดังที่แสดงไว้ด้านบน กำลังใช้จุดสิ้นสุดเซิร์ฟเวอร์คลาสภายใน InnerSimpleServerEndpoint ซึ่งเป็นสาธารณะโดยสมบูรณ์รวมถึงตัวสร้างด้วย และล้มเหลว แต่เมื่อใช้คลาสสแตนด์อโลน SimpleServerEndpoint (ดังที่แสดงไว้ด้านบน) ทุกอย่างทำงานได้ อะไรเกี่ยวกับจุดสิ้นสุดเซิร์ฟเวอร์คลาสภายในที่ทำให้เกิดความล้มเหลว ฉันกำลังทำอะไรผิดหรือนี่เป็นข้อบกพร่องใน Tyrus? - person Bill Balloni; 09.03.2015
comment
โอเค ฉันประเมินปัญหานี้เร็วเกินไป อย่างไรก็ตาม ในกรณีนี้ Tyrus ไม่ได้ทำอะไรเลย - การสแกนแพ็คเกจถูกมอบหมายให้กับคอนเทนเนอร์ Servlet - ดูคำอธิบายประกอบ @HandlesTypes javadoc ฉันไม่เห็นข้อยกเว้นของคลาสภายใน ดังนั้นนี่อาจเป็นปัญหาใน Servlet impl (หรือฉันอ่านข้อมูลจำเพาะไม่ถูกต้อง) อย่างไรก็ตาม คุณสามารถแก้ไขปัญหานี้ได้โดยใช้คลาส ServerApplicationConfig จาก javax.websocket.server API - person Pavel Bucek; 09.03.2015
comment
ขอบคุณพาเวล มีโค้ดตัวอย่างสำหรับการใช้ ServerApplicationConfig ในแอปพลิเคชันแบบสแตนด์อโลนหรือไม่ ฉันเล่นกับสิ่งนี้และได้รับข้อยกเว้นตัวชี้ null (TyrusServerConfiguration.java:191, tyrus เวอร์ชัน 1.10) ถ้าคุณมีลิงค์ไปยังสิ่งใดกรุณาส่งต่อ - person Bill Balloni; 09.03.2015
comment
แน่นอน ตัวอย่างที่นี่: github.com/tyrus-project/tyrus/blob/ - person Pavel Bucek; 10.03.2015

คลาสภายในควรเป็นแบบคงที่ ไม่เช่นนั้นจะไม่สามารถสร้างอินสแตนซ์ได้หากไม่มีอินสแตนซ์ของคลาสภายนอก ดูสิ่งนี้: https://www.javatpoint.com/why-we-use-static-class-in-java ดังนั้นหากคลาสที่ใส่คำอธิบายประกอบด้วย @ServerEndpoint ไม่ใช่สแตติก ก็จะไม่สามารถสร้างอินสแตนซ์ได้

person omid    schedule 22.07.2021