I'm trying to create a fairly simple WebSocket server using Netty 4.0.8. I have the basic handshake set up and working. But messages sent from a separate thread don't seem to be coming through to the client.
The way the client/server interaction works is that the client initiates the connection and then sends an initial message ("hello") over the WebSocket. The server responds immediately. This message comes through and is visible in the Chrome Dev Tools. After this message is written, I store the Channel in a ChannelGroup. This ChannelGroup is initialized like this:
this.broadcastGroup = new NioEventLoopGroup();
this.group = new DefaultChannelGroup("websocket", broadcastGroup.next());
and then the Channel is added like this:
group.add(ctx.channel());
In a separate thread (created outside of Netty), I do:
group.write(new TextWebSocketFrame("text"));
However, this message never appears in the Chrome Dev Tools.
I've tried debugging and I can see that when group.write() is called, the original Channel is in the group, but that's as far as I can get.
Check the ChannelFuture that was returned.. Most likely the ChannelFuture for the write was failed. Maybe you wrote it before the handshake was complete ?
Nevermind. Turns out the issue was that I neglected to call group.flush()
Related
I would like to do some one way streaming of data and am experimenting with SSE vs Websockets.
Using SSE form a golang server I'm finding it confusing on how to notify the client when sessions are finished. (eg the server has finished sending the events or the server suddenly goes offline or client looses connectivity)
One thing I need is to reliably know when these disconnect situations. Without using timeouts etc.
My experiments so far , when I take the server offline the client gets EOF. But I'm having trouble trying to figure out how to signal from the server to the client that a connection is closed / finished and then how to handle / read it? Is EOF a reliable way to determine a closed / error / finished state?
Many of the examples with SSE fail to show client good client connection handling.
Would this be easier with Websockets?
Any experiences suggestions most appreciated.
Thanks
The SSE standard requires that the browser reconnect, automatically, after N seconds, if the connection is lost or if the server deliberately closes the socket. (N defaults to 5 in Firefox, 3 in Chrome and Safari, last time I checked.) So, if that is desirable, you don't need to do anything. (In WebSockets you would have to implement this kind of reconnect for yourself.)
If that kind of reconnect is not desirable, you should instead send a message back to the client, saying "the show is over, go away". E.g. if you are streaming financial data, you might send that on a Friday evening, when the markets shut. The client should then intercept this message and close the connection from its side. (The socket will then disappear, so the server process will automatically get closed.)
In JavaScript, and assuming you are using JSON to send data, that would look something like:
var es = EventSource("/datasource");
es.addEventListener("message", function(e){
var d = JSON.parse(e.data);
if(d.shutdownRequest){
es.close();
es=null;
//Tell user what just happened.
}
else{
//Normal processing here
}
},false);
UPDATE:
You can find out when the reconnects are happening, by listening for the "close" event, then looking at the e.target.readyState
es.addEventListener("error", handleError, false);
function handleError(e){
if(e.target.readyState == 0)console.log("Reconnecting...");
if(e.target.readyState == 2)console.log("Giving up.");
}
No other information is available, but more importantly it cannot tell the difference between your server process deliberately closing the connection, your web server crashing, or your client's internet connection going down.
One other thing you can customize is the retry time, by having the the server send a retry:NN message. So if you don't want quick reconnections, but instead want at least 60 seconds between any reconnect attempts do this have your server send retry:60.
I am using spring/stomp/websocket framework to notify users of messages asynchronously. I have done this successfully. However, I would be get ACK from the client so that some server side action can take place when this is done.
The flow is roughly as flows:
Service notifies a specific user about a decision and updates a record in the DB with status = "notified"
Client receives the message (using stompClient.subscribe(...))
Client acknowledges that the message was received.
The service "knows" that this message was acknowledged and updates the status to "ACK" in the DB.
stompClient.connect({login:'guest', passcode:'guest'},
function(frame) {
setConnected(true);
**var headers = {ack: 'client'};**
...
stompClient.subscribe('/user/guest/response',function(notification) {
//doSomething
}), **headers**);
}
In the service, the message is sent:
this.messagingTemplate.convertAndSendToUser(user, "/response",msg, map);
Is there a way to handle the client ACK on the server side?
Alternatively, I tried to do a
stompClient.send("/app/response/ack/"+messageId);
on the client, in the method that handles the subscription, but in vain.
Can someone please tell me what is standard way to handle acknowledgments? I have been struggling with this for a a couple of days and any thoughts would be very helpful.
Thanks!
Use the ACK frame as per spec. The server sends an ack:some_id header, the client uses that some_id in the ACK frame.
The answer is no for simple broker.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html
The simple broker is great for getting started but supports only a
subset of STOMP commands (e.g. no acks, receipts, etc.), relies on a
simple message sending loop, and is not suitable for clustering. As an
alternative, applications can upgrade to using a full-featured message
broker.
Hello Freswitch Geeks,
I am facing some challenge handling events with the mode event_socket. I create a socket library that implements some of the features of the mod_event_socket in-built ESL. This what I did: I connect to Freeswitch, subscribe to events via events command and execute an originate command using the socket application. When the call is answered FS connects back to a daemon app runnning and based upon this guideline https://wiki.freeswitch.org/wiki/Event_Socket_Outbound#Using_Netcat I am able to handle the call.
However the issue I am facing is some of the events are not received by the deamon app(for instance channel_hangup_complete, record_stop...) I would like to know whether I am missing something.
Thanks
from the link you posted
it's a race,
sometimes the socket connection ends before the channel
the linger socket command was added to tell FS to wait for the last
channel event before ending the connection
just send the command
linger
This is an api command, so you will need to run "api linger" or something similar
I'm starting with Websockets and I have a problem.
I have a sails.js application that uses sockets to update the client side.
On the client side it makes an API call using socket.get("/api/v1/actor...") to bring all the items of the database. When I see what the WebSocket's traffic on the Chrome console:
As you can see, the connection has been established and the API call has been correctly done through the socket.
The problem is, there is no answer from the server, not even an error.
If I make the same API call using ajax, I get response, but it doesn't work using WebSockets.
Any idea what might be producing this behavior?
EDIT: I add here the code here that processes the request and this one here that sends the request, but the problem is that it never execute this code. I think we we are closer to the find the cause, since we think it has to do with a network problem. We figured there is an F5 reverse-proxy which is not properly set up to handle websockets
The answer didn't make any sense now that I've seen the code that's why I've edited it. I only answered because I could't comment on your question and ask you for the code.
Your calling code seems correct and the server side of things the process of response should be handled automatically by the framework, you only need to return some JSON in the controller method.
I instantiated a copy of the server (just changed the adapters to run it locally) and the server replied to the web socket requests (although I only tested the route '/index').
Normally when the problems are caused by a reverse proxy the socket simply refuses to connect and you can't even send data to server. Does the property "socket.socket.connected" returns true?
The best way to test is to write a small node application with socket.io client and test it in the same machine that the application server is running, then you can exclude network problems.
I need suggestion how to implement, if it is possible, with the Spring integration the following TCP flow:
Only the server side is need.
The TCP server waits for the incoming connection
On connection of the client, server sends data to the client
Client replies with response
Server may reply immediately with the new data or wait for external application events to send new packages to the client.
In groovy the code could be demonstrated as follow:
def serverSocket = new ServerSocket(...)
def connSocket = serverSocket.accept()
connSocket.outputStream.write(...)
while(true) {
def readBuffer = new byte[256]
connSocket.inputStream.read(readBuffer)
if(needToSendBack(readBuffer)) {
connSocket.outputStream.write(...)
}
}
def sendByDemand(def data) {
connSocket.outputStream.write(data)
}
The method sendByDemand could be invoked from the separate thread.
Here is a list of problems which I marked for myself, which prevents me to implement it with the Spring Integration (2.x version):
As far as I understand, the standard "Service Activator" approach cannot work in this scenario, since it is "connection events" driven. So when the application decides to send the new data to the client it cannot use the Service Activator
I have no "On TCP connection" event. I found that version 3.0 comes with the events support in this area, but since I cannot upgrade to 3.0, I implemented the connection check with the interceptors on the connection factory. However, when I know that client is connected, trying using the Direct Channels to send message fails with "no subscribers" error.
If someone could post possible Spring configuration for this scenario or point to the similar flow example it may be very helpful.
Your use case is possible, but it would make your life easier if you could upgrade to 3.0.
'Dispatcher has no subscribers' means there is no consumer subscribed to that channel.
You need to show your configuration; you must use collaborating channel adapters for this (not a gateway).
You need to capture the connectionId of the connection when it is established, and use it to populate the ip_connectionId header so the outbound channel adapter knows which socket to which to write the message.