I have a backend java code for websocket.
SessionEndpoint:
#ServerEndpoint("/session")
public class SessionEndpoint {
private static Set<SessionEndpoint> sessionEndpoints = new CopyOnWriteArraySet<>();
#OnMessage
public void onMessage(Session session, String sessionId) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("sessionId", sessionId);
sessionEndpoints.forEach(endpoint -> {
synchronized (endpoint) {
try {
session.getBasicRemote().sendObject(attributes);
} catch (IOException | EncodeException e) {
e.printStackTrace();
}
}
});
}
}
Trying to connect to websocket from javascript, code is given below.
let webSocket = new WebSocket('ws://localhost:9999/session');
webSocket.onopen = () => webSocket.send('hello');
webSocket.onmessage = function(response) {
console.log(response);
};
I get 404 response code while connecting to websocket. How should I connect to webscoket from javascript ?
Related
I have an existing socket server that listens on port 6868. It is written in Java.
I need to connect a client to the server. The client is coded in Javascript in my React app.
I have tried just about every possible combination of tutorials I have found on the internet but I still can't get the client to connect.
import * as io from "socket.io-client";
export default () => {
// eslint-disable-next-line no-restricted-globals
self.onmessage = (message) => {
const data = message.data;
try {
var socket = io("http://localhost:6868/");
} catch (error) {
console.log("do nothing: " + error);
}
};
};
No matter what, I get the same error: ReferenceError: socket_io_client__WEBPACK_IMPORTED_MODULE_0___default is not defined.
This is the version I am using as seen in package.json: "socket.io-client": "^4.4.0"
I installed it with this command: npm i socket.io-client
Turns out that socket.io can't be used to connect to the ServerSocket that I have in Java. To fix this, I changed ServerSocket to be a WebSocketServer.
Here is all of the code needed to make Java WebSocket connect with JavaScript client:
WebsocketServer.java
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
public class WebsocketServer extends WebSocketServer {
private static int TCP_PORT = 6868;
private static Set<WebSocket> conns;
public WebsocketServer() {
super(new InetSocketAddress(TCP_PORT));
conns = new HashSet<>();
}
#Override
public void onOpen(WebSocket conn, ClientHandshake handshake) {
conns.add(conn);
conn.send("hello!!");
System.out.println("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
conns.remove(conn);
System.out.println("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
#Override
public void onMessage(WebSocket conn, String message) {
System.out.println("Message from client: " + message);
for (WebSocket sock : conns) {
sock.send("SENDING BACK" + message);
}
}
#Override
public void onError(WebSocket conn, Exception ex) {
//ex.printStackTrace();
if (conn != null) {
conns.remove(conn);
// do some thing if required
}
System.out.println("ERROR from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
public static Set<WebSocket> getConns() {
return conns;
}
}
And launch the server from main() with new WebsocketServer().start();
client.js
var connection = new WebSocket("ws://127.0.0.1:6868");
connection.onopen = function () {
console.log("Connected!");
connection.send("Ping"); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log("WebSocket Error " + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log("Server: " + e.data);
};
And the dependency for the Java Web Socket:
<dependency>
<groupId>
org.java-websocket
</groupId>
<artifactId>
Java-WebSocket
</artifactId>
<version>
1.3.0
</version>
</dependency>
I am using net module to connect client with my server. And here is my code.
const Net = require('net');
client = Net.connect(parseInt(port), host, function() {
console.log('server connected')
})
console.log("ooooooooooooooooooooooooooooo")
client.on('data', function(chunk) {
let data = chunk.toString()
console.log(data)
});
client.on('error', function(error) {
console.error('error', error);
});
The issue is when I connect it with single client it doesn't give me data inside client.on('data' but when I connect it will two or more clients it gets connected and I am getting my data. Someone pls help.
If there any other module I can use ?
I have three Java TCP servers each running on their own thread, this particular one handles localhost connections from the NodeJS server which is mainly TEXT or JSON objects. It will read a command and respond.
The NodeJS server then sends that data back to the client browser using socket.io.
/*
* Handle the nodejs interaction on localhost port 2000
*/
public class DeviceServer3 extends Thread {
private static DeviceServer dev_server = null;
private boolean quit = false;
private final int port = 2000;
public DeviceServer3(DeviceServer server) {
dev_server = server; // store original server
}
public void quitSignal() { // safely shutdown thread
System.out.println("WLMedia Node Java Server exiting...");
quit = true;
while (dev_server.thread_count.get() != 0) {
try { Thread.sleep(5);
} catch (InterruptedException ex) {}
}
}
#Override
public void run() { // main thread
ServerSocket listen_socket = null;
while (!quit) {
try {
listen_socket = new ServerSocket(port);
//listen_socket.setSoTimeout(5000);
listen_socket.setReuseAddress(true);
while (!quit) {
Socket connection = listen_socket.accept();
checkSocket(connection);
}
} catch (IOException e) {
System.out.println("Node Server catch: " + e.getLocalizedMessage());
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
} finally {
try {
if (listen_socket != null) {
listen_socket.close();
}
} catch (IOException e) {
System.out.println("server finally: " + e.getMessage());
}
}
}
}
private void checkSocket(Socket socket) {
// Only allow 'localhost' connections
if (socket.getInetAddress().isLoopbackAddress()) {
handleSocket(socket); // TODO change to a thread
} else {
System.out.println("WARNING: Outside connection attempt from: "
+ socket.getInetAddress().toString());
}
try {
socket.close();
System.out.println("Port 2000 socket disconnected");
} catch (IOException e) {
e.printStackTrace();
}
}
private BufferedReader getBufferedReader(Socket socket)
throws IOException {
InputStreamReader is = new InputStreamReader(socket.getInputStream());
return new BufferedReader(is);
}
private BufferedWriter getBufferedWriter(Socket socket)
throws IOException {
OutputStreamWriter os = new OutputStreamWriter(socket.getOutputStream());
return new BufferedWriter(os);
}
// Safely here to handle the socket connection
private void handleSocket(Socket socket) {
System.out.println("Port 2000 socket connected");
try {
BufferedReader br = getBufferedReader(socket);
BufferedWriter bw = getBufferedWriter(socket);
String command = br.readLine();
switch (command) {
/* Media Manager */
case "media_areas":
System.out.println("NodeJS media_areas");
get_media_areas(br, bw);
break;
case "media_categories":
System.out.println("NodeJS media_categories");
get_media_categories(br, bw);
break;
/* Device manager */
case "devices_get":
System.out.println("NodeJS get_devices");
get_devices(br, bw);
break;
default:
System.out.println("NodeJS command not recognised: " + command);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* Handle commands
*/
// Command: media_areas
private void get_media_areas(BufferedReader br, BufferedWriter bw)
throws IOException {
JSONArray area_list = new JSONArray(); // create JSON array
System.out.println("Getting Area list");
synchronized (dev_server.library.media_lock) {
for (Area area : dev_server.library.media) {
area_list.put(area.name);
System.out.println("Area: " + area.name);
}
}
bw.write(area_list.toString()); // send JSON array back to NodeJS server
bw.flush(); // ensure a flush before the socket is closed
}
// ...
The issue I had was the data not being sent to the Node server, which using the flush() fixed that issue before the socket was closed.
This is a snipped from the Node server which connects to the Java TCP server and then sends the JSON data back to the clients browser.
const global = require("../global/global.js");
const login = require("../login/login");
const node_port = 2000;
const host = "localhost";
function m_get_media_areas(socket) {
// check user logged in (return to login page)
if (!login.check_logged_in(socket)) { return; }
client = new global.net.Socket(); // connect to Java TCP server
client.connect({port: node_port, host: host}, () =>
{ client.write("media_areas\n"); });
// send the JSON string to clients browser over socket.io
client.on("data", (data) => { socket.emit("media_areas", data); });
client.on("end", () => {});
client.on("error", () => { console.log("ERROR: getting areas"); });
}
module.exports = {
get_media_areas : m_get_media_areas,
// ...
}
On the clients browser side I just use socket.io to emit the command and then just listent for the event so that I can use the data.
// get area list
socket.emit("media_areas");
// media variables
media_area = "";
media_category = "";
media_videos = {}; // a JSON array of JSON objects
socket.on("media_areas", (res) => {
json = JSON.parse(new TextDecoder().decode(res));
$("#list_media_area").empty();
$("#list_media_category").empty();
$("#list_media_videos").empty();
json.forEach(area => {
if (area !== null && area !== "")
$("#list_media_area").append("<li>" + area);
});
media_area = "";
$("#list_media_area li").click(function() {
$(this).addClass("li_selected").siblings().removeClass("li_selected");
media_area = $(this).text();
console.log("Media Area Selected: " + media_area);
$("#accordion_video_category").click();
socket.emit("media_categories", {"area": media_area});
});
});
That's how I've managed to get around it and it works for me great.
The Java JSON library I used is:
https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.json%22%20AND%20a%3A%22json%22
Without more information on your server implementation it is difficult to answer this question directly. Here is a general example that should be helpful for you.
server.js
const net = require('net');
net.createServer(function(socket) {
// listen for data from the client
socket.on('data', function(data) {
console.log('data from client: ', String(data));
});
// write data to the client
socket.write('hello from the server\n');
}).listen('3000', function() {
console.log('server listening on 3000');
});
client.js
const net = require('net');
const socket = net.connect(3000, 'localhost')
// listen for data from the server
socket.on('data', function(data) {
console.log('data from server: ', String(data));
});
// write data to the server
socket.write('hello from the client\n');
First run node server.js then from a separate tab run node client.js. You should see the communication between the server and client. Another tool that may be helpful for you is telnet, which provides a simple tcp interface. You can test your server by using telnet localhost 3000
I am trying to implement a spring boot chat application using WebSocket stomp client. If I send messages from one device to 4,5 devices then some are getting the messages and some are not. Some can send messages but don't receive any message and some are working completely fine. My application is running on wildfly server and the URL is over https.
Here is my js file. From my JSP page I am calling sendMsg with all parameter and through render method I am attaching the response with JSP using Handlebars.
if (!window.location.origin) {
window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
}
const url = window.location.origin+contextPath;
let stompClient;
let selectedUser;
let newMessages = new Map();
function connectToChat(userName, topicName) {
console.log("connecting to chat...")
let socket = new SockJS(url + '/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log("connected to: " + frame);
stompClient.subscribe("/topic/decision-log", function (response) {
let data = JSON.parse(response.body);
var msg = data.message;
var fromlogin = data.message;
render(data.username, msg, fromlogin);
});
});
}
connectToChat("1", "decision-log");
function sendMsg(from, text, username) {
stompClient.send("/app/chat/" + from, {}, JSON.stringify({
fromLogin: from,
message: text,
topicName: topicName,
username: username
}));
}
function render(username, message, projectId) {
var templateResponse = Handlebars.compile($("#message-response-template").html());
var contextResponse = {
username: username,
response: message,
date: date,
projectId: projectId
};
setTimeout(function () {
$chatHistoryList.append(templateResponse(contextResponse));
scrollToBottom();
}.bind(this), 1500);
}
Here is my WebSocket configuration file:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app").enableSimpleBroker("/topic");
}
}
This is the controller. I always save all messages on the database that are coming through WebSocket that's why I can be sure that all devices can send messages as they have been saved on the database.
#Controller
#AllArgsConstructor
public class MessageController {
#Autowired
private SimpMessagingTemplate simpMessagingTemplate;
private final DecisionLogService decisionLogService;
#MessageMapping("/chat/{to}")
public void sendMessage(#DestinationVariable String to, MessageModel message, Authentication authentication ) {
simpMessagingTemplate.convertAndSend("/topic/decision-log", message);
AuthResponse userDetails = (AuthResponse) authentication.getDetails();
DecisionLogCreateRequest decisionLogCreateRequest = new DecisionLogCreateRequest();
decisionLogCreateRequest.setDecision(message.getMessage());
decisionLogCreateRequest.setProjectId(to);
ServiceResponseExtended<Boolean> response = decisionLogService.addDecisionLog(userDetails.getAccessToken(), decisionLogCreateRequest);
}
}
I can not find anything similar this issue. Please help me with right information and suggestion, and if anyone faced same kind of problem please share with me.
The problem was solved after configuring RabbitMQ Stomp Broker as a message broker instead of SimpleBroker.
Current WebSocket configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfiguration implements WebSocketMessageBrokerConfigurer{
#Value("${stomp-broker-relay-host}")
private String RELAY_HOST;
#Value("${stomp-broker-relay-port}")
private String RELAY_PORT;
#Value("${stomp-broker-login-user}")
private String USER;
#Value("${stomp-broker-login-pass}")
private String PASS;
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableStompBrokerRelay("/topic").setRelayHost(RELAY_HOST).setRelayPort(Integer.parseInt(RELAY_PORT)).setClientLogin(USER)
.setClientPasscode(PASS);
}
}
Reference:
https://medium.com/#rameez.s.shaikh/build-a-chat-application-using-spring-boot-websocket-rabbitmq-2b82c142f85a
https://www.javainuse.com/misc/rabbitmq-hello-world
I've been trying to implement a basic Spring WebSockets application following the official Spring guide. The files I have are the following:
WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/chat");
registry.setApplicationDestinationPrefixes("/message");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/ws-connect").setAllowedOrigins("*").withSockJS();
}
}
MessageController.java
#Controller
public class MessageController {
#MessageMapping(value = "/test")
#SendTo("/private")
public Message message(String messageText) {
Message message = new Message();
message.setMessage(messageText);r);
message.setTimestamp(new Date());
return message;
}
}
sockets.js
var stompClient = null;
function connect() {
var socket = new SockJS('http://localhost:8080/ws-connect');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/chat/private', function(message) {
console.log('Here');
console.log('Message is: ' + message);
});
console.log('Here2');
})
}
connect();
function sendMessage() {
stompClient.send('/message/test', {}, "Hello self!");;
}
I have a button in my index.html that when clicked calls the sendMessage function and I get a console log that the message has been sent, however I never get the reply in the subscribe function. The client successfully connects to the WebSocket server and I get this outputted in the console. What am I doing wrong?
Change /private to /chat/private
Change it like below :
#Controller
public class MessageController {
#MessageMapping(value = "/test")
#SendTo("/chat/private")
public Message message(String messageText) {
Message message = new Message();
message.setMessage(messageText);
message.setTimestamp(new Date());
return message;
}
}
I'm starting with signalr but got some trouble, my test server run at http://localhost:22660/ and my web run at
http://localhost:61963/.I got this error when connect from client to server:
GET http://localhost:61963/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1496809403215 404 (Not Found)
I already config: $.connection.hub.url = 'http://localhost:22660/signalr'; but not work, this my js code:
var connection = $.hubConnection();
$.connection.hub.url = 'http://localhost:22660/signalr';
var chatHub = connection.createHubProxy('ChatHub');
connection.start()
.done(function () { console.log('Now connected, connection ID=' + connection.id); })
.fail(function () { console.log('Could not connect'); });
Server:
namespace test
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableJSONP = true
};
map.RunSignalR(hubConfiguration);
});
}
}
}
namespace SignalRChat
{
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
}
}
I dont sure, but i think because i using different version of signalr (2.1.2 and 2.2.0). Using same version solved my problem.