tomcatwebsocket

Tomcat Embedded Websocket


I have problem to implement websocket with tomcat embedded .
this dependencies i used :

    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>11.0.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>11.0.4</version>
        </dependency>
    </dependencies>

this is my example code :

public class MainClass {
    private static final String contextPath = "";
    private static final String baseDir = "/tmp/tomcat";

    public static void main(String[] args) throws Exception {
        Tomcat tomcat = new Tomcat();
        tomcat.setHostname("0.0.0.0");
        tomcat.setPort(8080);
        tomcat.setBaseDir(baseDir);

        // Add the WebSocket initializer
        Context context = tomcat.addContext(contextPath, baseDir);
        context.addServletContainerInitializer(new WsSci(), null);

        // register servlet
        tomcat.addServlet(contextPath, "sample", new SampleServlet());
        context.addServletMappingDecoded("/sample", "sample");

        // Start the server
        tomcat.start();

        // Retrieve the ServerContainer and register the WebSocket endpoint
        ServerContainer serverContainer = (ServerContainer) context.getServletContext()
                .getAttribute("jakarta.websocket.server.ServerContainer");
        ServerEndpointConfig config = ServerEndpointConfig.Builder.create(SampleWebSocket.class, "/ws").build();
        serverContainer.addEndpoint(config);

        // Add the connector and await
        tomcat.getService().addConnector(tomcat.getConnector());
        tomcat.getServer().await();
    }
} 

this is SampleWebSocket :

public class SampleWebSocket extends Endpoint implements MessageHandler.Whole<String> {
    private Session session;

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        this.session = session;
    }

    @Override
    public void onMessage(String s) {
        try {
            System.out.println("Receive : " + s);
            session.getBasicRemote().sendText(LocalDateTime.now() + " Server response");
        } catch (IOException e) {
            throw new RuntimeException(e);
        } 
    }
}

I test that code with linux websocat command :

> websocat ws://localhost:8080/ws
websocat: WebSocketError: WebSocketError: Received unexpected status code (404 Not Found)

I can not found any example code or documentation about that ! How to use annotated classes ?


Solution

  • Project Tree

    ws-server-st
    ├── pom.xml
    ├── README.txt
    └── src
        └── main
            └── java
                └── com
                    └── example
                        └── wsserver
                            ├── Main.java
                            └── SampleWebSocket.java
    

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.example</groupId>
        <artifactId>websocket-server-jakarta-api</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <name>tomcat Examples :: Embedded :: WebSocket Server with Jakarta EE API</name>
    
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <tomcatVersion>11.0.4</tomcatVersion>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-core</artifactId>
                <version>${tomcatVersion}</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-websocket</artifactId>
                <version>${tomcatVersion}</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-jasper</artifactId>
                <version>${tomcatVersion}</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.tomcat.embed</groupId>
                <artifactId>tomcat-embed-el</artifactId>
                <version>${tomcatVersion}</version>
            </dependency>
    
            <dependency>
                <groupId>jakarta.servlet</groupId>
                <artifactId>jakarta.servlet-api</artifactId>
                <version>6.0.0</version>
                <scope>provided</scope>
            </dependency>
    
        </dependencies>
        <build>
            <finalName>websocket-server</finalName>
        </build>
    </project>
    

    Main.java

    package com.example.wsserver;
    
    import org.apache.catalina.startup.Tomcat;
    import org.apache.tomcat.websocket.server.WsSci;
    import java.io.File;
    import java.util.HashSet;
    import java.util.List;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Tomcat tomcat = new Tomcat();
            tomcat.setPort(8080);
            tomcat.getConnector().setProperty("address", "0.0.0.0");
    
            var context = tomcat.addWebapp("", new File(".").getAbsolutePath());
            context.addServletContainerInitializer(new WsSci(), new HashSet<>(List.of(SampleWebSocket.class)));
    
            tomcat.start();
            System.out.println("Tomcat startup is completed, listening to port 8080");
            tomcat.getServer().await();
        }
    }
    

    SampleWebSocket.java

    package com.example.wsserver;
    
    import jakarta.websocket.EndpointConfig;
    import jakarta.websocket.OnMessage;
    import jakarta.websocket.OnOpen;
    import jakarta.websocket.Session;
    import jakarta.websocket.server.ServerEndpoint;
    
    import java.io.IOException;
    import java.time.LocalDateTime;
    
    @ServerEndpoint("/ws")
    public class SampleWebSocket {
        private Session session;
    
        @OnOpen
        public void onOpen(Session session, EndpointConfig endpointConfig) {
            this.session = session;
        }
    
        @OnMessage
        public void onMessage(String s) {
            try {
                System.out.println("Receive : " + s);
                session.getBasicRemote().sendText(LocalDateTime.now() + " Server response");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    

    Build And Run

    Build

    mvn clean package
    mvn dependency:copy-dependencies -DoutputDirectory=target/libs
    

    Run

    java -cp "target/libs/*:target/websocket-server.jar" com.example.wsserver.Main
    

    Test

    websocat

    $ ./websocat.x86_64-unknown-linux-musl ws://localhost:8080/ws
    Hello
    2025-03-04T15:04:11.813977680 Server response
    World
    2025-03-04T15:04:14.734585249 Server response
    

    Server Output

    Receive : Hello
    
    Receive : World
    

    Debug And Check

    Check if there is any Java program running, and see if there is any Java program listening to port 8080.

    ss -tulnp | grep java

    $ ss -tulnp | grep java
    tcp   LISTEN 0      100                     *:8080             *:*    users:(("java",pid=47247,fd=13)) 
    

    lsof -i :8080

    $ lsof -i :8080
    COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    47247 demo   13u  IPv6 164794      0t0  TCP *:http-alt (LISTEN)