Abnormal CPU usage with WS server - java

I made a websocket server using Tyrus implementation and it takes 50 % of the cpu usage but I don't know why. At first I thought it was the processes besides but after that, I wrote an extremely simple ws server after that and it is still the same...
Here is a screenshot from the resource monitor (Windows Server 2008 R2) :
The server runs on a Intel(R) Xeon(R) CPU E5-2650 0 # 2.00 Ghz with 4GB Memory
I don't know the exact architecture...
The code of the simplified ws server :
package wstest;
import javax.websocket.DeploymentException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.glassfish.tyrus.server.Server;
public class Wstest {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
runServer();
}
private static void runServer() {
Server server = new Server("localhost", 8025, "/tp", null, wsendpoint.class);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
logger.info("Server stopped.");
}
});
try {
server.start();
logger.info("Server started.");
while (true) { }
} catch (DeploymentException ex) {
logger.fatal(ex);
}
}
}
package wstest;
import javax.websocket.CloseReason;
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 org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
#ServerEndpoint(
value = "/test"
)
public class wsendpoint {
private static final Logger logger = LogManager.getLogger();
#OnOpen
public void onOpen(Session session) {
logger.info("Client " + session.getId() + " connected");
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
logger.info("Client " + session.getId() + " disconnected.");
}
#OnMessage
public void onMessage(String request, Session session) {
logger.info(session.getId() + " sent message : " + request);
}
#OnError
public void onError(Session session, Throwable t) {
logger.error("Error !", t);
}
}
Here are the librairies I used :

There is no limit on the while loop that keeps your server running. Because of this, the full cpu usage goes to making this as fast as possible, while nothing is happening. I'm pretty sure adding Thread.sleep(5) would solve the problem. Fixed it most of the times I needed to make a server that listened for a socket. However, I don't know if this is best practice.

Related

Why I can't call methods outside of my websocket server in Java?

I have websocket server class where I want to print when user connects. It works without a problem, however if I want to execute a method outside of this websocket server, it doesn't print and closes the client's connection and prints out java RuntimeException error.
package com.rupla.myapp.endpoint;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.sql.SQLException;
import javax.websocket.EncodeException;
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 com.rupla.myapp.encoders.MessageEncoder;
import com.rupla.myapp.http.MyOtherClas;
import com.rupla.myapp.encoders.MessageDecoder;
#ServerEndpoint(value = "/chatnow", encoders = MessageEncoder.class, decoders = MessageDecoder.class)
public class WebSocketServer {
#OnOpen
public void onOpen(Session session) {
extracted(session);
}
private void extracted(Session session) {
System.out.println("Session Opened (Client to Server) - ID: " + session.getId());
}
#OnMessage
public void handleTextMessage(String message, Session s) throws IOException {
System.out.println("New Text Message Received: " + message + " - From session: " + s.getId());
//So here we send client's message to the client - This works
s.getBasicRemote().sendText("Server: " + message);
try {
// Here I try to print "hello" but from 'MyOtherClas'.class using printTest() method
MyOtherClas.printTest();
//Right after this code, server closes the connection to the client and doesn't print anything
}
catch(Exception e) {
System.out.println("fail: "+e);
}
}
/**
* If I would call this method below, it would work since it's in the same class (but why?)
*/
private void printInsideClas() {
System.out.println("hello");
}
#OnClose
public void onClose(Session session) throws IOException, EncodeException {
System.out.println("Session Closed");
}
#OnError
public void onError(Throwable t) {
System.out.println("onError: " + t);
}
}
Pretty basic websocket server for java. However when I run this on my tomcat 9.0 and connect with javascript client and try to send message from my client to the server. It closes the connection between server and client and then prints this error.
Session Opened (Client to Server) - ID: 4
New Text Message Received: asd - From session: 4
onError: java.lang.RuntimeException: org/apache/http/Header
Session Closed
I tried to google this for few days for now but still I have no answers, I really need help with this.
The exception is in a server-side webservices stack. The exception is saying that it cannot load a core class that is part of Apache HTTPComponents.
Here are some possible explanations:
Your server-side runtime is missing the JAR file.
The JAR is present, but it is not on the right runtime classpath.
The Header class depends on some other class that has failed class initialization. If this has happened, there should be evidence earlier in the logfile.
The JAR file you should be looking for is "httpcore-.jar" or the equivalent from the old Jakarta project.
Figure out which of the above has happened, and you are close to solving the problem.

Use Actors to send data to Akka websockets

I am using Akka websockets to push data to some client.
This is what I have done so far:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.http.javadsl.ConnectHttp;
import akka.http.javadsl.Http;
import akka.http.javadsl.ServerBinding;
import akka.http.javadsl.model.HttpRequest;
import akka.http.javadsl.model.HttpResponse;
import akka.http.javadsl.model.ws.Message;
import akka.http.javadsl.model.ws.WebSocket;
import akka.japi.Function;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import akka.stream.javadsl.Flow;
import akka.stream.javadsl.Sink;
import akka.stream.javadsl.Source;
public class Server {
public static HttpResponse handleRequest(HttpRequest request) {
System.out.println("Handling request to " + request.getUri());
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeterHello();
return WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
return HttpResponse.create().withStatus(404);
}
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
try {
final Materializer materializer = ActorMaterializer.create(system);
final Function<HttpRequest, HttpResponse> handler = request -> handleRequest(request);
CompletionStage<ServerBinding> serverBindingFuture = Http.get(system).bindAndHandleSync(handler,
ConnectHttp.toHost("localhost", 8080), materializer);
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
} finally {
system.terminate();
}
}
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSource(Sink.ignore(),
Source.single(new akka.http.scaladsl.model.ws.TextMessage.Strict("Hello!")));
}
}
At the client side, I am successfully receiving a 'Hello!' message.
However, now I want to send data dynamically (preferably from an Actor), something like this:
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
public class PushActor extends UntypedActor {
#Override
public void onReceive(Object message) {
if (message instanceof String) {
String statusChangeMessage = (String) message;
// How to push this message to a socket ??
} else {
System.out.println(String.format("'%s':\nReceived unknown message '%s'!", selfActorPath, message));
}
}
}
I am unable to find any example regarding this online.
The following is the software stack being used:
Java 1.8
akka-http 10.0.10
One - not necessarily very elegant - way of doing this is to use Source.actorRef and send the materialized actor somewhere (maybe a router actor?) depending on your requirements.
public static Flow<Message, Message, NotUsed> greeterHello() {
return Flow.fromSinkAndSourceMat(Sink.ignore(),
Source.actorRef(100, OverflowStrategy.fail()),
Keep.right()).mapMaterializedValue( /* send your actorRef to a router? */);
}
Whoever receives the actorRefs of the connected clients must be responsible for routing messages to them.

Need help implementing WebSocket in java

I'm working on an Web Application in which multiple users work on the same data (source is sql database)
I'm using
Netbeans 8.0.2
Tomcat 8.0.28
Maven 4.0.0
jquery-2.1.4
I want the server to push a message to all clients which have opened a WebSocket Connection to my server.
I found a lot of guides/tutorials on how to implement WebSockets but they all rely on the Client pushing something to the Server.
I just need the server to push a message to the Client.
Can any1 provide a short example on how to to this??
It just needs to be:
Client opens SocketConnection
JavaClass establishes connection
JavaClass method sends message/data to client
EDIT:
My setup right now:
On application startup I do the following:
startup.java
package com.mycompany.ssp;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.servlet.ServletContextEvent;
public class Startup implements javax.servlet.ServletContextListener {
private static WebSocketServer socket_server = null;
// create singleton object Socket
getSocket();
public static WebSocketServer getSocket(){
if(socket_server == null) {
socket_server = new WebSocketServer();
}
return socket_server;
}
}
WebSocketServer.java
package com.mycompany.ssp;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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 = "/socket")
public class WebSocketServer {
private static final Logger LOGGER = Logger.getLogger(WebSocketServer.class.getName());
private List<Session> session_list = new ArrayList<Session>();
WebSocketServer socket_server = Startup.getSocket();
public WebSocketServer() {
}
#OnOpen
public void onOpen(Session session) {
LOGGER.log(Level.INFO, "New connection with client: {0}",
session.getId());
socket_server.session_list.add(session);
}
#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());
socket_server.session_list.remove(session);
}
#OnError
public void onError(Throwable exception, Session session) {
LOGGER.log(Level.INFO, "Error for client: {0}", session.getId());
}
public void send(String message) throws IOException{
for(Session session: socket_server.session_list){
session.getBasicRemote().sendText(message);
}
}
}
I get an Error when trying to start my application.
Why does it happen?
Well, the Method getSocket() loops multiple times and everytime after
socket_server = new WebSocketServer(); the variable socket_server is still null, which should be initialized though.
Netbeans Apache TomcatEE Log:
SEVERE [http-nio-8080-exec-1050] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class com.mycompany.ssp.Startup
java.lang.StackOverflowError
Does any1 have an idea why this is happening??
var websocket=new websocket(websocket_url);
Java Code
#ServerEndpoint(value = "/websocket/one")
public class WebsocketEndPoint {
public static List clients=new ArrayList();
#OnOpen
public void OnOpen(Session session, EndpointConfig config)
throws IOException {
//Save the endpoints session that opened the connection in List
}
#OnMessage
public void OnMessage(Session session, String message) {
}
#OnClose
public void OnClose(Session session, CloseReason reason) {
//remove from list
}
#OnError
public void OnError(Session session, Throwable throwable) {
}
}
}
3.
class Sender{
public void send(String message){
for(Session session:WebsocketEndPoint.clients){
session.getBasicRemote().sendText(message);
}
}
}
Hope this helps
And in Javascript u can use onMessage to get the message

Can't connect client to server using Spring Websocket

I've written a Blackjack server in java which starts up fine, but I'm having trouble writing a separate java client to connect to my server. I've followed the Spring Websocket documentation and examples and it looks like my client connects without any errors and I'd expect it to hit the afterConnected() method, but it doesn't get to that point. The client runs and finishes with no errors. Any idea what I'm doing wrong?
WebSocketConfig.java on the server side:
package com.lactaoen.blackjack.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic", "/queue");
registry.setApplicationDestinationPrefixes("/app");
registry.setUserDestinationPrefix("/user");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/connect").withSockJS();
}
}
Client side:
package com.lactaoen.blackjack.client;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.simp.stomp.*;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.RestTemplateXhrTransport;
import org.springframework.web.socket.sockjs.client.SockJsClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import java.util.ArrayList;
import java.util.List;
public class BlackjackClient {
public static void main(String[] args) {
List<Transport> transports = new ArrayList<>();
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
transports.add(new RestTemplateXhrTransport());
SockJsClient sockJsClient = new SockJsClient(transports);
String stompUrl = "ws://localhost:8080/connect";
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
stompClient.setMessageConverter(new StringMessageConverter());
stompClient.connect(stompUrl, new BlackjackSessionHandler());
}
private static class BlackjackSessionHandler extends StompSessionHandlerAdapter {
#Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
// I'd expect it to print this out, but it doesn't get here
System.out.println("Hello, world!");
}
}
}
the main method of the client side is finishing before to connect.
put a Thread.sleep(60000) in the last line of your main method, it's should work
The client will close the connection after communication complete(send or receive), you should block the thread to ensure the application not close.
Add this at the end of main method:
//block the thread
CountDownLatch latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

Akka future with Play Framework

I am trying to use Akka future with play framework to connect to a remote akka system
. After running the system the akka future gives me a warning that one argument is left.
the code are below :
this is the [lay controller code:
p
ackage controllers;
import com.typesafe.config.ConfigFactory;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import play.*;
import play.mvc.*;
import views.html.*;
public class Application extends Controller {
public static Result index() throws InterruptedException {
System.out.println(" Local Node Called0");
ActorSystem csystem = ActorSystem.create("Application", ConfigFactory.load().getConfig("LocalNode"));
ActorRef localNode = csystem.actorOf(new Props(LocalNode.class));
System.out.println(" Local Node Called1");
localNode.tell("Hello");
System.out.println(" Local Node Called2");
Thread.sleep(5000);
csystem.shutdown();
return ok(index.render("I am OK"));
}
}
this is the play framework local actor node
package controllers;
import akka.actor.;
import akka.dispatch.Await;
import akka.dispatch.Future;
import akka.event.Logging;
import akka.event.LoggingAdapter;
import akka.util.Duration;
import akka.util.Timeout;
import akka.pattern.;
public class LocalNode extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
Timeout timeout = new Timeout(Duration.parse("20 seconds"));
ActorRef masterActor;
public void preStart()
{
/* Get reference to Master Node*/
masterActor =
getContext().actorFor("akka://MasterNode#127.0.0.1:2552/user/masterActor");
}
#Override
public void onReceive(Object message) throws Exception {
System.out.println(" Future called ");
Future<Object> future = Patterns.ask(masterActor , message.toString(), timeout);
String result = (String) Await.result(future, timeout.duration());
log.info("Messagefrom Server", result.toString());
}
}
this is the remote akka system master nide
package Rubine_Cluster;
import com.typesafe.config.ConfigFactory;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.kernel.Bootable;
/**
* Hello world!
*
*/
public class MasterNode implements Bootable
{
final ActorSystem system;
public MasterNode() {
system = ActorSystem.create("MasterNode", ConfigFactory.load()
.getConfig("masterNode"));
ActorRef masterActor = system.actorOf(new Props(MasterActor.class),"masterActor");
System.out.println(" Master Node is called ");
}
public void startup() {
}
public void shutdown() {
system.shutdown();
}
}
this is the akka remote system MasterActor
package Rubine_Cluster;
import akka.actor.*;
public class MasterActor extends UntypedActor {
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
// Get reference to the message sender and reply back
getSender().tell(message + " got something");
}
}
}
this is the message from the play framewrok
[INFO] [09/30/2012 16:47:25.669] [Application-akka.actor.default-dispatcher-1] [
akka://Application/user/$a] Messagefrom Server WARNING arguments left: 1
help is needed cos I am suppose to meet the assignment deadline
thanks to all
The "arguments left: 1" warning is due to the following line:
log.info("Messagefrom Server", result.toString())
You're passing unused params to the logger. It should be this instead:
log.info("Messagefrom Server {}", result.toString())
Try to give a name to your actor in Play:
ActorRef localNode = csystem.actorOf(new Props(LocalNode.class), "localNode");
And also note that if you need to access the Akka system from Play, it is better to use:
ActorSystem csystem = Akka.system();
instead of:
ActorSystem csystem = ActorSystem.create("Application", ConfigFactory.load().getConfig("LocalNode"));

Categories

Resources