I have a Spring integration server running on a tcp-inbound-gateway and a client that connects to the server using regular java sockets.
The client connects to the server, the server processes the request and then sends the response. The client reads in the response, then closes the connection using socket.close().
On the server side I have a tcp-connection-event-inbound-channel-adapter configured and I see this:
TcpConnectionExceptionEvent [source=org.springframework.integration.ip.tcp.connection.TcpNetConnection#2294e71d, cause=org.springframework.integration.ip.tcp.serializer.SoftEndOfStreamException: Stream closed between payloads], [factory=crLfServer, connectionId=127.0.0.1:52292:5556:add2ff2a-b4ff-410d-8e60-d6b1a388044e]
Is this normal behavior?
Yes; it's normal - we emit application events whenever an exception occurs on a socket, the SoftEndOfStreamException occurs when the socket is closed "normally" (i.e. between messages).
We could, I suppose, suppress that particular event, but some find it useful.
Related
I'm writing a client which communicates with multiple server via gRPC. The data transfer works absolutely fine but I'm getting an exception on client side when one of the server stops abruptly. I would like to know if there is any error handling in gRPC library which can handle this server disconnection and do a clean exit from client side.
I can see methods like bool IsCancelled() const which could be used on server side to get status about client disconnection.
I need a similar method to be used on client to get notified about server disconnection.
I'm looking at a proto file which has a bidirectional stream between the client and the server. Does this mean that the client and server can send and receive messages arbitrarily? I'm more confused about the server side. How can the server send data over this bidirectional stream arbitrarily? What would be the trigger?
Thanks!
From the docs:
In a bidirectional streaming RPC, again the call is initiated by the
client calling the method and the server receiving the client
metadata, method name, and deadline. Again the server can choose to
send back its initial metadata or wait for the client to start sending
requests.
What happens next depends on the application, as the client and server
can read and write in any order - the streams operate completely
independently. [...]
This means: the client would establish the connection to the server and you'd then have a connection on wich both parties can read/write.
I have a Spring Boot Tomcat server that is handling websocket connections from clients that are using:
SocketRocket
Tyrus
I find that the close code provided by the server is often not the close code read by the client.
For SocketRocket, I close the websocket at the server with code 1000, and the client often reads 1001.
For Tyrus, I close the websocket with code 1011, and the client reads either 1006 or 1011.
Descriptions of close codes from RFC 6455:
1000 indicates a normal closure, meaning that the purpose for
which the connection was established has been fulfilled.
1001 indicates that an endpoint is "going away", such as a server
going down or a browser having navigated away from a page.
1006 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed abnormally, e.g., without sending or
receiving a Close control frame.
1011 indicates that a server is terminating the connection because
it encountered an unexpected condition that prevented it from
fulfilling the request.
I have verified the outgoing close codes using Wireshark at the server.
Is the close code just unreliable as a means of passing information from the server to the client? Do I need to implement something at the application layer that passes this information before closing websockets?
This is just a guess, but the WebSocket clients you listed may not implement the closing handshake correctly.
Why don't you try nv-websocket-client to see what's happening? onDisconnected method of the library's listener interface (WebSocketListener) is defined as below.
void onDisconnected(
WebSocket websocket,
WebSocketFrame serverCloseFrame,
WebSocketFrame clientCloseFrame,
boolean closedByServer);
The second argument serverCloseFrame is the close frame which the server sent to the client, and the third argument clientCloseFrame is the close frame which the client sent to the server. In normal cases, as required by the specification, payloads of the two close frames are identical.
I'm using uwsgi's websockets support and so far it's looking great, the server detects when the client disconnects and the client as well when the server goes down. But i'm concerned this will not work in every case/browser.
In other frameworks, namely sockjs, the connection is monitored by sending regular messages that work as heartbeats/pings. But uwsgi sends PING/PONG frames (ie. not regular messages/control frames) according to the websockets spec and so from the client side i have no way to know when the last ping was received from the server. So my question is this:
If the connection is dropped or blocked by some proxy will browsers reliably (ie. Chrome, IE, Firefox, Opera) detect no PING was received from the server and signal the connection as down or should i implement some additional ping/pong system so that the connection is detected as closed from the client side?
Thanks
You are totally right. There is no way from client side to track or send ping/pongs. So if the connection drops, the server is able of detecting this condition through the ping/pong, but the client is let hung... until it tries to send something and the underlying TCP mechanism detect that the other side is not ACKnowledging its packets.
Therefore, if the client application expects to be "listening" most of the time, it may be convenient to implement a keep alive system that works "both ways" as Stephen Clearly explains in the link you posted. But, this keep alive system would be part of your application layer, rather than part of the transport layer as ping/pongs.
For example you can have a message "{token:'whatever'}" that the server and client just echoes with a 5 seconds delay. The client should have a timer with a 10 seconds timeout that stops every time that messages is received and starts every time the message is echoed, if the timer triggers, the connection can be consider dropped.
Although browsers that implement the same RFC as uWSGI should detect reliably when the server closes the connection cleanly they won't detect when the connection is interrupted midway (half open connections)t. So from what i understand we should employ an extra mechanism like application level pings.
I have a webapp, which is running in a browser. That webapp is connected to a server, which uses websockets. So the communication between the server and my client/browser is based on websockets. If some magic event occurs on the server, some webservice sends a new XML / JSON to my webapp and the new data gets displayed.
But how do i, as the client / browser, know if the connection is stil alive? Lets say i do not get any new XML for about 30 seconds. How would i know if the connection is closed/broken/server offline or everything is fine, but on the server himself no new magic event occured.
A websocket connection object has a readyState field which will tell you if the connection is still active (from the dart documentation). The readyState can be either
0 - connection not yet established
1 - conncetion established
2 - in closing handshake
3 - connection closed or could not open
You can also define an event handler for the websocket close event if this is something you'd like to handle (try to reconnect, etc).
3 ways:
rely on TCP to detect loss of connectivity, which will ultimately pop up in JS onclose event
send WebSocket pings from server .. browsers will reply with WS pongs, loss of connectivity is probably more robustly detected also on client side
send app level heartbeats from browser to server, server need to have logic to reply. you can't trigger WS pings from browsers (in JS)