Server Sent Events Close Connection - Spring Boot - javascript

i have one question about SSEEmitter in Java Spring Boot.
I have following code to etablish connection between client and server in Java Spring Boot. I have set the timeout of the SseEmitter - object to max value of long.
Now following scenary occurrs: I close the tab in the browser and the sseemitter object on the server don't close. So many objects are on the server. This leads to memory issues.
#RequestMapping(value = "/subscribe", consumes = MediaType.ALL_VALUE)
public SseEmitter subscribe() {
System.out.println("SUBSCRIBE CALLED!");
System.out.println(emitters.size());
SseEmitter x = new SseEmitter(Long.MAX_VALUE);
try {
x.send(SseEmitter.event().name("INIT"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
x.onCompletion(()->{
System.out.println("ON COMPLETION CALLED!");
emitters.remove(x);
});
x.onTimeout(()->{
System.out.println("ON TIMEOUT CALLED!");
emitters.remove(x);
});
emitters.add(x);
return x;
}
How can I say the client to close the object?
Kind regards

I assume you are using "emitters" to send future updates. Try to complete the emitter and remove it from "emimtter" in the catch (IOException) block where you send the emitter update:

Related

Read string received from JavaScript WebSocket using Java InputStreamReader

I am trying to read value received from JavaScript WebSocket using Java
I have this JavaScript code:
const socket = new WebSocket("wss://localhost:7999"); // start
socket.addEventListener("open", (event) => {
socket.send("Hello!");
});
socket.addEventListener("message", (event) => {
console.log("Received message.");
});
And this Java code:
import java.io.*;
import java.net.*;
class Server {
public static void main(String[] args) throws Exception {
ServerSocket s = new ServerSocket(7999);
Socket client = s.accept();
System.out.println("I am in!");
InputStream inputStream = client.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream, "UTF-8");
BufferedReader in = new BufferedReader(reader);
String readLine;
while ((readLine = in.readLine()) != null) {
System.out.println(readLine);
}
}
}
However, upon launching the server and client code, I am receiving this value:
I am in!
���
�.isֿ���pO?��-4/P�P����- ���Q�`�:���x���wG�Z��x��v�##�6���,�+̩�0�/̨�$�#�
� �(�'����=<5/�
}�� localhost�
��http/1.1
3+)�� �-l-h������ۥ n�}�>�zUZ�Ğ�-+
My goal is to read the value Hello, that I have sent using socket.send.
Does anyone know how to fix this problem?
Thanks.
ServerSocket is quite low level construct for handling TCP connections.
Websocket even though it starts as an HTTP request it requires server to request connection upgrade, there is handshaking, then handling websocket frames, including some internal frames like ping/pong.
Unless you plan to implement that entire functionality, I'd suggest you to not use raw ServerSocket but instead use a library that provides websocket support out of the box.
Some options that I could point you to are:
netty
vert.x

webSocket.send() inside webSocket.onopen always fails

I'm starting with WebSockets and, to try things off, I built a minuscule WebSocket server in C# (using WebSocketSharp) and an html as a client to connect to it.
On the client I have this code:
const webSocket = new WebSocket("ws://localhost:51036/test");
webSocket.onopen = e => {
webSocket.send("hello :D");
console.log("Socket connection opened!");
}
This send() call never works — it sometimes result in an exception in the C# server, most other times it is just ignored as if nothing was ever received on the server's end. However, any send() I call afterwards (e.g. with a button) works fine, and send() inside onopen also works fine if I place it inside a timeout of just 200ms. If I don't call any send() onopen, and just call it later via a button, it always works fine (so it's not a 'first call always fails' issue).
On the C# side, the code is very simple:
public class TestWS : WebSocketBehavior {
protected override void OnMessage (MessageEventArgs e) {
System.Diagnostics.Debug.WriteLine($"Client message: {e.Data}");
Send($"String length: {e.Data.Length} [msg received: {e.Data}]");
}
}
public static class Sockets {
public const string SERVER_ROUTE = "ws://localhost:51036";
private static WebSocketServer socket;
public static void Start () {
socket = new WebSocketServer(SERVER_ROUTE);
socket.AddWebSocketService<TestWS>("/test");
socket.Start();
System.Diagnostics.Debug.WriteLine($"Server started on {SERVER_ROUTE}");
}
public static void Stop () {
socket.Stop();
}
}
The exception in question is this one:
2021-09-06 19:59:06|Fatal|WebSocket.<startReceiving>b__175_2:0|WebSocketSharp.WebSocketException: The header of a frame cannot be read from the stream.
at WebSocketSharp.WebSocketFrame.processHeader(Byte[] header)
at WebSocketSharp.WebSocketFrame.<>c__DisplayClass73_0.<readHeaderAsync>b__0(Byte[] bytes)
at WebSocketSharp.Ext.<>c__DisplayClass55_0.<ReadBytesAsync>b__0(IAsyncResult ar)

Unable to get open sessions other than current client in Java websocket.

I'm programming a simple web socket chat application. When I open the socket, I send a message to join the room with a name and the web socket returns the updated room object showing the current users names.
I'm trying to send the updated room with user names to all open connections, so if I open 2 browser tabs, I should see the users added by one tab reflected in the other, however I don't see that. When debugging on the session.getOpenSessions() I only ever see a single session. I would expect to also see the connection of the other browser tab.
JS
window.onload = function() {
var socket = new WebSocket('ws://localhost:8080/chat/roomName');
socket.onmessage = function(event) {
document.getElementById('message').message.innerHTML = event.data;
};
socket.onopen = function(event) {
socket.send('{"command":"join", "value":"MyName"}');
};
}
Web socket code
#OnOpen
public void onOpen(Session session, #PathParam("roomName") String roomName) throws IOException, EncodeException {
currentSession = session;
session.getBasicRemote().sendObject(getRoom(roomName));
}
On load
for (Session session: currentSession.getOpenSessions()){
try {
if(session.isOpen() && session.getUserProperties().get("roomName").equals(room.getRoomName())){
session.getBasicRemote().sendObject(room);
}
} catch (Exception e){
e.printStackTrace();
}
}
By default websocket creates a new server (Endpoint) for every request from client.so when you are doing session.getOpenSessions() returns the same session.
make the server endpoint singleton .link

C# WebSocket - No response from client during handshake

I'm attempting to write a C# WebSocket server for an application that interacts upon browser input.
This is the code:
class Program {
static void Main(string[] args) {
var listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 42001);
listener.Start();
using(var client = listener.AcceptTcpClient())
using(var stream = client.GetStream())
using(var reader = new StreamReader(stream))
using(var writer = new StreamWriter(stream)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine();
if (new Regex("^GET").IsMatch(line)) {
line = reader.ReadLine();
if (new Regex("^Sec-WebSocket-Key: ").IsMatch(line)) {
String key = new Regex("(^Sec-WebSocket-Key\\: |\\r\\n)").Replace(line, "");
key = Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")));
writer.WriteLine("HTTP/1.1 101 Switching Protocols");
writer.WriteLine("Upgrade: websocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("Sec-WebSocket-Accept: " + key);
writer.WriteLine("Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits");
writer.WriteLine("WebSocket-Origin: http://127.0.0.1");
writer.WriteLine("WebSocket-Location: ws://localhost:42001/websocket");
writer.WriteLine("");
}
}
}
}
listener.Stop();
}
}
... and:
var ws = new WebSocket('ws://localhost:42001/websocket');
ws.onopen = function() {
console.log('connected');
};
ws.onmessage = function(e) {
console.log(e.data);
};
ws.onerror = function(e) {
console.log(e);
};
ws.onclose = function() {
console.log("closed");
};
On execution, the TPCListener successfully accepts the TCPClient and reads the incoming HTTP request. It parses the Key, generates the correct Accept token, but the JS - window native - WebSocket seems to have gone flat out bonkers: it does not answer no matter what it receives.
I would expect it throwing an error upon sending a HTTP/1.1 400 Bad Request, but nothing at all happens. It just goes mute.
Checking out Chrome Dev Tools' Networking tab, I do only see the websocket outgoing GET request, but no incoming packets - is that supposed to happen?
If I forcefully close the application, WebSocket throws this exception:
WebSocket connection to 'ws://localhost:42001/websocket' failed: Error during WebSocket handshake: net::ERR_CONNECTION_RESET.
What am I missing here? Thank you all in advance.
Also, I'm not using Net.WebSockets because it is available since .NET 4.5, and my application targets systems from Windows 7 to the current build of Windows 10.
well... how far does your C# code get? My first bet would be on buffering - you don't flush the writer or stream, so I would expect them to be holding onto data while stuck in the top of the while loop, but frankly it shouldn't be a while loop in the first place - you only get one handshake per socket, not many. You could try adding flushes after the blank line, and you should make sure the Socket itself has buffering disabled (NoDelay = true;) - but: fundamentally this isn't a good way to write a web-socket server. Apart from anything else, the data will cease to be text if the handshake succeeds, so having a TextReader is a very bad thing. Frankly, you should be dealing with raw Socket / byte[] data here, IMO (having implemented this very thing several times).

WebSocketException: "I/O operation has been aborted"

Trying to implement a basic WebSockets channel with a JavScript client and an ASP.NET server. The client code goes:
function Connect()
{
var ws = new WebSocket("ws://" + window.location.host + "/callback.aspx");
ws.onmessage = function (a) { alert("Message"); };
ws.onopen = function (a) { alert("Open"); };
ws.onerror = function (a) { alert("Error"); };
}
Callback.aspx is a basic ASP.NET web page, and it goes:
protected void Page_Load(object sender, EventArgs e)
{
if (HttpContext.Current.IsWebSocketRequest)
{
HttpContext.Current.AcceptWebSocketRequest(SocketProc);
}
}
private static async Task SocketProc(AspNetWebSocketContext a)
{
try
{
ArraySegment<byte> Buffer = new ArraySegment<byte>(new Byte[1024]);
while (true)
{
WebSocketReceiveResult res = await a.WebSocket.ReceiveAsync(Buffer, CancellationToken.None);
if (a.WebSocket.State != WebSocketState.Open)
return;
}
}
catch (Exception exc)
{
Debug.WriteLine(exc);
}
}
When I try to connect from the client, the Page_Load is invoked, then SocketProc is invoked, but then ReceiveAsync immediately throws the following exception:
System.Net.WebSockets.WebSocketException (0x800703E3): The I/O operation has been aborted because of either a thread exit or an application request
at System.Web.WebSockets.WebSocketPipe.<>c__DisplayClass9_0.<ReadFragmentAsync>b__0(Int32 hrError, Int32 cbIO, Boolean fUtf8Encoded, Boolean fFinalFragment, Boolean fClose)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.WebSockets.AspNetWebSocket.<DoWork>d__45`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.WebSockets.AspNetWebSocket.<>c__DisplayClass36_0.<<ReceiveAsyncImpl>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at CleanProxy.callback.<SocketProc>d__2.MoveNext() in C:\dev\CleanModel\CleanProxy\callback.aspx.cs:line 37
On the client, OnOpen fires, then OnError.
If I catch the exception immediately around ReceiveAsync, the WebSocket object comes out of it closed.
What am I missing here? Testing on Windows Server 2016, both in IIS Express and IIS proper.
EDIT: I've been testing with built-in IE, but I've now tried with Chrome and got a different error. This time, there's no exception, ReceiveAsync returns an object with MessageType=Close, CloseStatus=ProtocolError. On the client, there's an error in Chrome console:
WebSocket connection to 'ws://localhost:53329/callback.aspx' failed: Invalid frame header
EDIT2: it somehow worked with an HTTP handler instead of an ASPX page. Freaky. There's no requirement to use classic ASP.NET, so this'll do for now, but the issue will probably remain unsolved.

Categories