I try run this example:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/chat")
public class ChatServer {
private static final Logger LOGGER =
Logger.getLogger(ChatServer.class.getName());
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
}
#OnMessage
public String onMessage(String message, Session session) {
LOGGER.log(Level.INFO, "New message from Client [{0}]: {1}",
new Object[] {session.getId(), message});
return "Server received [" + message + "]";
}
#OnClose
public void onClose(Session session) {
LOGGER.log(Level.INFO, "Close connection for client: {0}",
session.getId());
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
}
I use Tomcat 7.0.47, I check link: ws://localhost/Tests/chat.
Do I need register this websocket or add some things in web.xml?
Any idea why is not working for me?
I had the same problem trying to use WebSocket API on Tomcat 7.0.47. The error message being displayed client side wasn't any help at all and my server side endpoint was never being created.
After much wasted time I found it was due to way I had set the dependency for javax.websocket-api. I'm using Maven which has the default scope as compile which causes problems as Tomcat has the websocket-api.jar in its lib folder. Setting the dependency to provided solved it.
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
Hope this helps
It's also worth noting that if running behind Apache you will need mod_proxy_wstunnel and if using IIS you will need version 8.0 as anything prior does not support websockets.
Related
I want to setup a WebSocket Connection to upload a lot of very small files (1kb-50mb) to a web-application.
My Web-App runs in Wildfly, and the rest/https based components work fine, however my Websocket connection returns 404 everytime or 200 when I try.
Here's the code for my Endpoint:
package com.my.package;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.util.logging.Level;
import java.util.logging.Logger;
#ServerEndpoint("/smallfiles/socket")
public class WebsocketApi {
private static final long serialVersionUID = 2356475533479775725L;
private static final Logger logger = Logger.getLogger(WebsocketApi.class.getName());
private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());
#OnOpen
public void onOpen(Session session) {
// Set max buffer size
session.setMaxBinaryMessageBufferSize(1024 * 512);
// Add session to the connected sessions set
clients.add(session);
logger.log(Level.INFO,"Client " + session.getId() + " connected.");
}
#OnClose
public void onClose(Session session) {
// Remove session from the connected sessions set
clients.remove(session);
logger.log(Level.INFO,"Client " + session.getId() + " disconnected.");
}
#OnError
public void onError(Throwable error) {
logger.log(Level.SEVERE,error.getMessage());
}
#OnMessage
public void processUpload(byte[] uploadData, Session session) {
try {
if (session.isOpen()) {
// Wrap a byte array into a buffer
ByteBuffer buf = ByteBuffer.wrap(uploadData);
logger.log(Level.INFO,"Receiving Data");
//session.getBasicRemote().sendBinary(buf);
}
} catch (Exception e) {
try {
session.close();
} catch (Exception e1) {
logger.log(Level.SEVERE,"Failed to close Session. ",e1);
}
}
}
}
I had the Idea that maybe this is cuased by Apache, since our Wildfly is running behind an apache which works as reverse-proxy, so I added the Websocket Endpoints in my https-gw.conf:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName repName
SSLProxyEngine On
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
ProxyPass /Application/ http://127.0.0.1:8080/Application/
ProxyPassReverse /Application/ http://127.0.0.1:8080/Application/
ProxyPass /smallfiles/socket/ ws://127.0.0.1:8080/websocket/
ProxyPassReverse /smallfiles/socket/ ws://127.0.0.1:8080/websocket/
ProxyPass /Application/smallfiles/socket/ ws://127.0.0.1:8080/Application/websocket/
ProxyPassReverse /Application/smallfiles/socket/ ws://127.0.0.1:8080/Application/websocket/
SetEnv proxy-sendcl 10000000
SetEnv proxy-sendchunked
# Server Certificate:
SSLCertificateFile /etc/apache2/ssl.crt/host.net.cer
# Server Private Key:
SSLCertificateKeyFile /etc/apache2/ssl.key/host.net.key
# Certificate Authority (CA):
SSLCACertificateFile /etc/apache2/ssl.crt/my_ca.crt
</VirtualHost>
</IfModule>
However whenever I try to access the Websocket through Javascript, I get the following Problems:
ws = new WebSocket("wss://my.server.net/")
WebSocket {url: "wss://my.server.net/", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
WebSocket connection to 'wss://my.application.net/' failed: Error during
WebSocket handshake: Unexpected response code: 200
or
ws = new WebSocket("wss://my.server.net/smallfiles/socket")
WebSocket {url: "wss://my.server.net/smallfiles/socket", readyState: 0, bufferedAmount: 0, onopen: null, onerror: null, …}
WebSocket connection to 'wss://my.server.net/smallfiles/socket' failed:
Error during WebSocket handshake: Unexpected response code: 404
I also checked the Post from User #cayz, but sadly I don't really see, what the users solution meant.
Does anyone know where I am having my blackage?
EDIT:
I also checked the wildfly logs, and wildfly registers the endpoint.
2020-02-04 19:33:44,647 INFO [io.undertow.websockets.jsr] (ServerService Thread Pool -- 113) UT026003: Adding annotated server endpoint class com.my.package.WebsocketApi for path /smallfiles/socket
I'm writing a WebSocket client in a java application, using the Jetty 9.4.18 libraries.
I'm pretty new to WebSockets, so I started testing using the two sample classes from the Jetty documentation, connecting to echo.websocket.org
The test runs fine when I connect without SSL, but if fails when the connection is done to wss://echo.websocket.org
I always get the same exception:
java.io.EOFException: HttpConnectionOverHTTP#50371e9d::DecryptedEndPoint#6dc65fc2{echo.websocket.org/174.129.224.73:443<->/192.168.1.34:60521,OPEN,fill=-,flush=C,to=226/0}
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.earlyEOF(HttpReceiverOverHTTP.java:338)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:1551)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.shutdown(HttpReceiverOverHTTP.java:209)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.process(HttpReceiverOverHTTP.java:147)
at org.eclipse.jetty.client.http.HttpReceiverOverHTTP.receive(HttpReceiverOverHTTP.java:73)
at org.eclipse.jetty.client.http.HttpChannelOverHTTP.receive(HttpChannelOverHTTP.java:133)
at org.eclipse.jetty.client.http.HttpConnectionOverHTTP.onFillable(HttpConnectionOverHTTP.java:155)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.onFillable(SslConnection.java:411)
at org.eclipse.jetty.io.ssl.SslConnection.onFillable(SslConnection.java:305)
at org.eclipse.jetty.io.ssl.SslConnection$2.succeeded(SslConnection.java:159)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
It looks like the server closes without answering to the handshake request.
I am aware of SslContextFactory, but my understanding is that it should be used only if you need your own TrustStore or KeyStore, or for other special cases.
Note also that after some failed attempt I downloaded another websocket implementation from https://github.com/TooTallNate/Java-WebSocket, and it works fine with both ws and wss, without setting anything specific for SSL.
However for this project I'm bind to use Jetty.
The code I'm using is exactly the sample from Jetty documentation at https://www.eclipse.org/jetty/documentation/9.4.x/jetty-websocket-client-api.html
the only change I did was to add an onError method to SimpleEchoSocket, that dumps the full exception stack.
Am I missing something?
Thanks in advance!
Unfortunately, websocket.org (and Kaazing host/proxy) has a bunch of TLS issues at this point in time, so using their public servers are not sane choice right now.
Here's a different demo, also using TLS and WebSocket, against a stackexchange server with a proper and sane TLS/SSL implementation.
This was written against Jetty 9.4.18.v20190429
package org.eclipse.jetty.demo;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.WebSocketClient;
#WebSocket
public class SecureClientSocket
{
private static final Logger LOG = Log.getLogger(SecureClientSocket.class);
public static void main(String[] args)
{
String url = "wss://qa.sockets.stackexchange.com/";
SslContextFactory ssl = new SslContextFactory.Client();
ssl.setEndpointIdentificationAlgorithm("HTTPS");
HttpClient http = new HttpClient(ssl);
WebSocketClient client = new WebSocketClient(http);
try
{
http.start();
client.start();
SecureClientSocket socket = new SecureClientSocket();
Future<Session> fut = client.connect(socket, URI.create(url));
Session session = fut.get();
session.getRemote().sendString("Hello");
session.getRemote().sendString("155-questions-active");
}
catch (Throwable t)
{
LOG.warn(t);
}
finally
{
stop(http);
stop(client);
}
}
private static void stop(LifeCycle lifeCycle)
{
try
{
lifeCycle.stop();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#OnWebSocketConnect
public void onConnect(Session sess)
{
LOG.info("onConnect({})", sess);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason)
{
LOG.info("onClose({}, {})", statusCode, reason);
}
#OnWebSocketError
public void onError(Throwable cause)
{
LOG.warn(cause);
}
#OnWebSocketMessage
public void onMessage(String msg)
{
LOG.info("onMessage() - {}", msg);
}
}
I am using websockets for the first time on a javafx project, when I start the program the session is set to the local variable session, but after when I call the sendMessage function the session is back to null. Below please find my client class
package myclient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
#ClientEndpoint
public class Client extends Application {
private static final Logger LOGGER = Logger.getLogger(Client.class.getName());
private Session session;
#OnOpen
public void onOpen(Session session){
this.session = session;
System.out.println("Opened Session " + this.session);
}
#OnClose
public void onClose(){
System.out.println("Closed Session " + this.session);
}
#OnMessage
public void onMessage(String msg){
System.out.println("Websocket message received! " + msg);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLClient.fxml"));
Scene scene = new Scene(root);
connectToWebSocket();
stage.setScene(scene);
stage.show();
}
private void connectToWebSocket() {
System.out.println("Client WebSocket initialized>> " + this.session);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
URI uri = URI.create("ws://localhost:8080/Server/endpoint");
container.connectToServer(this, uri);
}
catch (DeploymentException | IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
System.exit(-1);
}
}
public void sendMessage(String message) throws IOException{
if(this.session != null){
System.out.println(message + ", " + this.session);
this.session.getBasicRemote().sendText(message);
}
else {
System.out.println("Session is null");
}
}
public static void main(String[] args) {
launch(args);
}
}
Any suggestions?
Thanks in advance
I think I now do know the answer to this.
You are probably using tomcat or some other server for this. When you see "tomcat" in this answer, please insert the name of your actually used server.
When a connection to your websocket is opened, tomcat will create an instance of the websocket (your Client) class by itself. This means, the onOpen-Method will be called and it will look as if it was you who created the instance, who opened the connection, when really you did not. Tomcat did.
This in turn means, that when you call sendMessage on your Client instance, the session will be null, because this object never connected anywhere.
Oh, and you don't have access to the connected instance that was created by tomcat.
One way of fixing this would be to do all the work inside the onOpen-Method, however that is not practical. You may want to put the work in another method and call it from onOpen. That way, the instance created by tomcat will do the necessary work.
In my project I needed to poll on an MQTT-Topic and render the data on a website (university assignment). I did the polling in a separate class, resulting in hard to debug errors whenever trying to send received data with my sendMessage-method.
I hope this answer does clear this up a little, if not for you, maybe at least for future generations having the same university assignment...
The WebSocket is working perfectly in localhost (tomcat) . but when i host (Openshift - tomcat) it immediately disconnects and not firing the onMessage method. I've checked the header and the status code is Status Code:101 Switching Protocols.
Here is my socket.
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
#ServerEndpoint("/TestSocket")
public class TestSocket {
#OnOpen
public void onOpen(Session session) {
try {
session.getBasicRemote().sendText("Connected");
} catch (IOException e) {
e.printStackTrace();
}
}
#OnMessage
public void onMessage(Session session, String message) {
System.out.println("New message : " + message);
try {
session.getBasicRemote().sendText("Message received -> :" + message);
} catch (IOException e) {
e.printStackTrace();
}
}
#OnClose
public void onClose() {
System.out.println("Closed");
}
}
Here is the live socket ws://shifar-shifz.rhcloud.com:8000/MyTestProject/testWebSocket. I can't figure out what the problem is. Please help me.
EDIT
I am using the Tomcat 7 (JBoss EWS 2.0) cartridge. The project was deployed through a WAR file.
I found it's working when i remove the web-socket-api.jar from the lib after the artifact building. I think the Openshift already contain another web-socket-api.jar in their server. and can't contain any duplicate of the existing jars/libs.
My IDE : NetBeans, GlassFish.
I am trying to understand how GlassFish execute and run the Endpoint!
I understand Glassfish as a webserver creates new Endpoint instance for each connection, and the Set : peers in the code appears as one global variable for every instance of endpoint.
My question is : how to add another global variable(s) so every instance of endpoint can access it?
enter code here
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/echo")
public class EchoServer {
/**
* #OnOpen allows us to intercept the creation of a new session.
* The session class allows us to send data to the user.
* In the method onOpen, we'll let the user know that the handshake was
* successful.
*/
private static final Set<Session > peers = Collections.synchronizedSet(new HashSet<Session >());
#OnOpen
public void onOpen(Session session){
System.out.println(session.getId() + " has opened a connection");
try {
peers.add(session);
session.getBasicRemote().sendText("Connection Established");
} catch (IOException ex) {
ex.printStackTrace();
}
}
#OnMessage
public void onMessage(String message, Session session) throws IOException{
System.out.println("Message from " + session.getId() + ": " + message);
for (Session peer : peers) {
peer.aplayer.getBasicRemote().sendText(" Message from " + session.getId()+" : "+message);
}
}`enter code here`
#OnClose
public void onClose(Session session){
System.out.println("Session " +session.getId()+" has ended");
peers.remove(session);
}
}