I'm newbie to the web-socket programming...
I have the following JavaScript client code:
var connection = new WebSocket('ws://localhost:8080/OmegaThings/registerdevice');
connection.onopen = function () {
console.log("Socket has been opened state = " + connection.readyState);
connection.send('Ping'); // Send the message 'Ping' to the server
connection.send('Websocket client');
};
console.log("Socket has been opened state = " + connection.readyState);
connection.send('finish');
// 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);
};
Java endpoint:
#ServerEndpoint("/registerdevice")
public class RegisterDeviceEndPoint
{
private static final Logger LOG = Logger.getLogger(RegisterDeviceEndPoint.class.getName());
#OnOpen
public void connectionOpened()
{
LOG.log(Level.INFO, "******************connection opened**************");
}
#OnMessage
public synchronized void processMessage(Session session, String message)
{
LOG.log(Level.INFO, "received message: {0}", message);
}
#OnClose
public void connectionClosed()
{
LOG.log(Level.INFO, "connection closed");
}
}
on the firefox console I got the following output:
"Socket has been opened state = 1"
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
"Socket has been opened state = 0"
on the GlassFish server log I got "ping" and "Websocket client", but the connection closed after onopen event exit(not sure), thus, the last word "finish" doesn't appear on the log and the error occurs.
I want to know if my code is correct?
What causes the error? javascript code, GlassFish server configuration or the java endpoint code?
Try to change the glassfish 8080 port, eg: 8887, or make sure Your antivirus/other application are not using port 80, I previously had experience where my server websocket was blocked by antivirus which using port 80.
Related
I am using Spring Integration with Spring Boot. I have a TCP Client [TcpNetClientConnectionFactory] with TcpOutboundGateway setup. I can see the below warnings in Production[No publisher available to publish].
Log Snippet
Based on my checking this warning is shown when the org.springframework.context.ApplicationEventPublisher is null.
Code:
#Bean
#ServiceActivator(inputChannel = "a04A08OutgoingChannel")
public MessageHandler a04A08OutgoingGate() {
final TcpOutboundGateway gate = new TcpOutboundGateway();
// Connection configured in client mode to send the message over the TCP socket
// and wait for acknowledgement
gate.setConnectionFactory(connectionFactory.connectionFactory(host, port));
gate.setReplyChannelName("a04A08ReplyToString");
gate.setRemoteTimeout(60_000);
return gate;
}
#Transformer(inputChannel = "a04A08ReplyToString")
public String transform(byte[] bytes) {
String reply = new String(bytes);
log.debug("transform - a04A08ReplyToString channel " + reply);
return new String(bytes);
}
public String outgoingMessage(String message) {
String reply = null;
log.info("Message being Sent : " + message);
try {
// Send the message to the TCP socket and wait for acknowledgement
reply = a04a08OutgoingGateway.sendMessage(message);
} catch (ConnectException e) {
log.error(e.getMessage(),e);
}
log.info("Acknowledgement received : " + reply);
return reply;
}
ConnectionFactory.java:
public AbstractClientConnectionFactory connectionFactory(String host, int port) {
final AbstractClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory(host, port);
connectionFactory.setSerializer(customDeserializer);
connectionFactory.setDeserializer(customDeserializer);
//connectionFactory.setSoKeepAlive(true);
connectionFactory.setSingleUse(true);// This property when set to false ensures that one shared connection is used for all
// request/replies and each caller blocks waiting for the socket
return connectionFactory;
}
Edit 1 : Included CustomDeserializer.java
#Override
public void serialize(String object, OutputStream outputStream) throws IOException {
log.info("[Serialize] Serializing data : length ==> " + object.length());
outputStream.write(object.getBytes());
log.info("[Serialize] data posted to stream");
}
#Override
public byte[] deserialize(InputStream inputStream) throws IOException {
log.info("[Deserialize] De-Serializing data");
BufferedReader input = new BufferedReader(new InputStreamReader(inputStream));
StringBuffer stringbuffer = new StringBuffer();
while (true) {
int value = input.read();
if (value == 28) {
break;
} else {
if (value != -1) {
stringbuffer.append((char) value + "");
} else {
break;
}
}
}
log.info("[deserialize.readFromSocket()]: " + stringbuffer.toString());
return stringbuffer.toString().getBytes();
}
The TCP server is able to receive the messages sent by the TCP client. [Note: TCP server is a different system and not maintained by us].I have 2 queries.
Will this warning have any impact? Can anyone elaborate on the warning? Even when the warnings are seen the messages from TCP client are sent to TCP server without any issues.
We faced below issue (Caused by: org.springframework.messaging.MessagingException: Exception while awaiting reply; nested exception is java.net.SocketTimeoutException: Read timed out) in production recently. When we faced the below exception, telnet to the server port worked but the messages were not received by the server. The issue was automatically resolved when the TCP server was restarted. My question : Is this issue related to the warning in point #1. These warnings are seen even on normal days when the messages are sent to the server without any issues.
Error logs
P.S: I also checked the post : No publisher available to publish TcpConnectionOpenEvent / TcpConnectionCloseEvent
It is not related; sounds like a server problem if restarting it solves it.
The connection factory must be declared as a #Bean so that spring can inject the event publisher.
I am trying to use a Java Socket Server with socket.io-client, but it has an erratic behavior from the moment of the connection. It manages to stablish connection, but then this exception is thrown in Angular:
GET https://127.0.0.1:1532/socket.io/?EIO=4&transport=polling&t=N__rEfS net::ERR_SSL_PROTOCOL_ERROR
And the Server in Java only receives scrambled text repatedly
and the Client starts connecting and disconnecting over and over again. Why is this happening? Is there any way to get a cleaner Socket connection from Angular 13 to Java?
I use this Java Socket Server for many other applications and it works perfectly for everything else but this.
This is the routine that reads the Java Server:
void handleClientRequest() {
try{
mBufferIn = new BufferedReader(new InputStreamReader( socket.getInputStream()));
mBufferOut = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
//in this while the client listens for the messages sent by the server
while (clientRun) {
String clientMessage = mBufferIn.readLine();
if (clientMessage != null && mMessageListener != null) {
mMessageListener.messageReceived(clientMessage);
}
}
} catch(Exception e){
System.out.printf("%s: Unexpected client disconnection. Reason:%n", accountId);
e.printStackTrace();
}
}
And this is the Angular code:
this.socket = io('https://127.0.0.1:1532');
this.socket.on('connect', () => {
const engine = this.socket.io.engine;
console.log(engine.transport.name); // in most cases, prints "polling"
engine.once('upgrade', () => {
// called when the transport is upgraded (i.e. from HTTP long-polling to WebSocket)
console.log(engine.transport.name); // in most cases, prints "websocket"
});
engine.on('packet', ({ }) => {
// called for each packet received
});
engine.on('packetCreate', ({ }) => {
// called for each packet sent
});
engine.on('drain', () => {
// called when the write buffer is drained
});
engine.on('close', (reason: any) => {
// called when the underlying connection is closed
});
});
Code taken from https://socket.io/docs/v4/client-socket-instance/
Socket IO is a communication protocol implemented on the top of websocket
from my understanding (correct me if im wrong) you are using raw socket in java.
So very likely that "scrambled" text that you are receiving, is part of https handshake.
My suggestion as way forward, will be to use library that handles websocket connections.
I am using netty-socket.io and I implemented the server like the demo.
I receive onConnect event both on server and client, but when I sent a message {message: message} I don't get anything on the server event though I see the message being sent in the network tab.
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(9092);
final SocketIOServer server = new SocketIOServer(config);
server.addConnectListener(socketIOClient -> System.out.println("Connection test"));
server.addEventListener("messageevent", MessageEventObject.class, new DataListener<MessageEventObject>() {
#Override
public void onData(SocketIOClient socketIOClient, MessageEventObject messageEventObject, AckRequest ackRequest) throws Exception {
System.out.println("message received!");
}
});
server.start();
My MessageEventObject has String message property, constructor getters and setters, looking the same as client-sided.
And this is my websocket service client-sided:
export class WebsocketService {
private socket;
private subject = new Subject < any > ();
constructor() {
console.log('test!');
}
public connect(host: string, port: number) {
this.socket = io(`http://${host}:${port}`, {
'reconnection': false
});
this.socket.on('connect', this.onConnected);
this.socket.on('connect_error', this.onConnectionFailure);
}
public getConnectionStateUpdate(): Observable < any > {
return this.subject.asObservable();
}
public sendMessage(message: string) {
console.log('test');
this.socket.emit('messageevent', {
message: message
});
}
private onConnected = () => {
this.subject.next({
connected: true
});
}
private onConnectionFailure = () => {
this.subject.next({
connected: false
});
}
}
Is there anything that I did wrong?
I would love to answer my own question after tons of debugging and breaking my head, my laziness to use Engine IO with tomcat or jetty, and just wanting to use that awesome netty package which does not require any servlets, I tried to fix it and figure out.
At first I thought it was the client's protocol version, so I used the exact same client as the demo shows on their github page here but that didn't work so the problem is server-sided.
It appears that your object (MessageEventObject) must have a default empty constructor aswell in addition to your other constructors, probably because netty tries to build an empty object and it fails which causes an exception that you don't see.
I use websockets and Glassfish. I call start() funcion on load page. When start function contains alert it sends the message to the server but when I don't put the alert it doesn't work. I can't figure out why.
java script
function start() {
alert('a'); //this alert
webSocket.send('start_server');
}
function onMessage(event) {
document.getElementById('messages').innerHTML
+= event.data;
}
server side
#OnMessage
public void onMessage(String message, Session session)
throws IOException, InterruptedException {
System.out.println("Message recieved");
session.getBasicRemote().sendText(message);
}
#OnOpen
public void onOpen() {
System.out.println("Client connected");
}
Where do you initialize the web-socket on the client side?
The alert suspends execution until you click ok - so i guess your order of execution is wrong (initialize the websocket before webSocket.send)
You may send data after the WebSocket#open event happend.
var connection = new WebSocket(...)
connection.onopen = function () {
connection.send('Ping');
};
Source: html5rocks
I have a websocket endpoint as
#ServerEndpoint("/tweets")
public class TweetStreamServer {
private static final Logger LOGGER = LoggerFactory.getLogger(TweetStreamServer.class);
#OnMessage
public void tweets(final String message, final Session session) throws IOException, InterruptedException {
System.out.println("session id:" + session.getId() + ", search term: " + message);
final Client twitterClient = TwitterHoseBird.getInstance(message);
while (!session.getOpenSessions().isEmpty()) {
for (final Session s : session.getOpenSessions()) {
if (twitterClient.isDone()) {
System.out.println("Twitter Client Done, waiting ...");
}
s.getBasicRemote().sendText(TwitterHoseBird.getMsgQueue().take());
}
}
}
}
I deploy this on WildFly 8.1.0 Final. Then I open multiple tabs on Chrome, Safari and run the following
var connection = new WebSocket('ws://127.0.0.1:8080/tweetstream-1.0-SNAPSHOT/tweets');
connection.onopen = function () {
connection.send('germany');
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
connection.onclose = function (e) {
console.log('closing session');
};
Then all the tabs start receiving data from server.
Then when I do connection.close(); on one of the tabs, only that connection breaks while all the other tabs are still receiving the data
But if I close one of the tabs (in any browser), all the sessions that were open in all the other tabs close session with closing session message
Question
- Is it not a valid use case that if user closes a tab in one browser, all the other tabs should still receive the data?
- Do you see any bug/issue with what I am doing?
- How can I fix this issue?
Thanks
Instead of using
s.getBasicRemote().sendText(TwitterHoseBird.getMsgQueue().take());
change it to
s.getAsyncRemote().sendText(TwitterHoseBird.getMsgQueue().take());
and everything else would just workout fine