Index: TFP-WebServer/WebServer/src/SSE/AbsEvent.cs
===================================================================
--- TFP-WebServer/WebServer/src/SSE/AbsEvent.cs	(revision 467)
+++ TFP-WebServer/WebServer/src/SSE/AbsEvent.cs	(revision 487)
@@ -1,15 +1,10 @@
 using System;
 using System.Collections.Generic;
-using System.IO;
-using System.Net.Sockets;
 using System.Text;
 using Webserver.UrlHandlers;
-using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
 
 namespace Webserver.SSE {
 	public abstract class AbsEvent {
 		private const int encodingBufferSize = 1024 * 1024;
-		private const int keepAliveIntervalSeconds = 10;
-		private static readonly byte[] keepAliveData = Encoding.UTF8.GetBytes (": KeepAlive\n\n");
 
 		private readonly SseHandler parent;
@@ -18,7 +13,6 @@
 		private readonly byte[] encodingBuffer;
 		private readonly StringBuilder stringBuilder = new StringBuilder ();
-		private DateTime lastMessageSent;
 
-		private readonly List<HttpListenerResponse> openStreams = new List<HttpListenerResponse> ();
+		private readonly List<SseClient> openClients = new List<SseClient> ();
 
 		private readonly BlockingQueue<(string _eventName, string _data)> sendQueue =
@@ -37,9 +31,9 @@
 		}
 
-		public void AddListener (HttpListenerResponse _resp) {
+		public void AddListener (SseClient _client) {
 			totalOpened++;
 			currentlyOpen++;
 
-			openStreams.Add (_resp);
+			openClients.Add (_client);
 		}
 
@@ -50,6 +44,4 @@
 
 		public void ProcessSendQueue () {
-			bool dataSent = false;
-			
 			while (sendQueue.HasData ()) {
 				(string eventName, string data) = sendQueue.Dequeue ();
@@ -81,55 +73,20 @@
 				}
 
-				dataSent = true;
-
 				sendBufToListeners (buf, bytesToSend);
-			}
-
-			DateTime now = DateTime.Now;
-			if (dataSent) {
-				lastMessageSent = now;
-			} else if ((now - lastMessageSent).TotalSeconds >= keepAliveIntervalSeconds) {
-				sendBufToListeners (keepAliveData, keepAliveData.Length);
-				lastMessageSent = now;
 			}
 		}
 
 		private void sendBufToListeners (byte[] _bytes, int _bytesToSend) {
-			for (int i = openStreams.Count - 1; i >= 0; i--) {
-				HttpListenerResponse resp = openStreams [i];
-				try {
-					if (resp.OutputStream.CanWrite) {
-						resp.OutputStream.Write (_bytes, 0, _bytesToSend);
-						resp.OutputStream.Flush ();
-					} else {
-						currentlyOpen--;
-						totalClosed++;
+			for (int i = openClients.Count - 1; i >= 0; i--) {
+				ESseClientWriteResult writeResult = openClients [i].Write (_bytes, _bytesToSend);
+				if (writeResult == ESseClientWriteResult.Ok) {
+					continue;
+				}
 
-						logError ("Can not write to endpoint, closing", true);
-						openStreams.RemoveAt (i);
-						resp.Close ();
-					}
-				} catch (IOException e) {
-					currentlyOpen--;
-					totalClosed++;
+				currentlyOpen--;
+				totalClosed++;
 
-					openStreams.RemoveAt (i);
-
-					if (e.InnerException is SocketException se) {
-						if (se.SocketErrorCode != SocketError.ConnectionAborted && se.SocketErrorCode != SocketError.Shutdown) {
-							logError ($"SocketError ({se.SocketErrorCode.ToStringCached ()}) while trying to write", true);
-						}
-					} else {
-						logError ("IOException while trying to write:", true);
-						Log.Exception (e);
-					}
-				} catch (Exception e) {
-					currentlyOpen--;
-					totalClosed++;
-
-					openStreams.RemoveAt (i);
-					logError ("Exception while trying to write:", true);
-					Log.Exception (e);
-					resp.Close ();
+				if (writeResult == ESseClientWriteResult.Error) {
+					logError ("Can not write to endpoint, closing", true);
 				}
 			}
@@ -143,4 +100,8 @@
 
 		public virtual int DefaultPermissionLevel () => 0;
+
+		public void ClientClosed (SseClient _client) {
+			openClients.Remove (_client);
+		}
 	}
 }
Index: TFP-WebServer/WebServer/src/SSE/SseClient.cs
===================================================================
--- TFP-WebServer/WebServer/src/SSE/SseClient.cs	(revision 487)
+++ TFP-WebServer/WebServer/src/SSE/SseClient.cs	(revision 487)
@@ -0,0 +1,85 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+using SpaceWizards.HttpListener;
+using Webserver.UrlHandlers;
+
+namespace Webserver.SSE {
+    public enum ESseClientWriteResult {
+        Ok,
+        Closed,
+        Error,
+    }
+    
+    public class SseClient {
+        private const int keepAliveIntervalSeconds = 10;
+        private static readonly byte[] keepAliveData = Encoding.UTF8.GetBytes (": KeepAlive\n\n");
+
+        private readonly SseHandler parent;
+        private readonly HttpListenerResponse response;
+        private DateTime lastMessageSent = DateTime.Now;
+
+        public SseClient (SseHandler _parent, HttpListenerResponse _response) {
+            parent = _parent;
+            response = _response;
+            
+            // Keep the request open
+            _response.SendChunked = true;
+
+            _response.AddHeader ("Content-Type", "text/event-stream");
+            _response.OutputStream.Flush ();
+        }
+
+        public ESseClientWriteResult Write (byte[] _bytes, int _bytesToSend) {
+            HttpListenerResponse resp = response;
+            try {
+                if (!resp.OutputStream.CanWrite) {
+                    parent.ClientClosed (this);
+                    resp.Close ();
+                    
+                    return ESseClientWriteResult.Closed;
+                }
+
+                resp.OutputStream.Write (_bytes, 0, _bytesToSend);
+                resp.OutputStream.Flush ();
+                lastMessageSent = DateTime.Now;
+                return ESseClientWriteResult.Ok;
+            } catch (IOException e) {
+                parent.ClientClosed (this);
+
+                if (e.InnerException is SocketException se) {
+                    if (se.SocketErrorCode == SocketError.ConnectionAborted || se.SocketErrorCode == SocketError.Shutdown) {
+                        return ESseClientWriteResult.Closed;
+                    }
+
+                    Log.Error ($"[Web] [SSE] SocketError ({se.SocketErrorCode.ToStringCached ()}) while trying to write", true);
+                    return ESseClientWriteResult.Error;
+                }
+
+                Log.Error ("[Web] [SSE] IOException while trying to write:", true);
+                Log.Exception (e);
+                return ESseClientWriteResult.Error;
+            } catch (Exception e) {
+                parent.ClientClosed (this);
+                resp.Close ();
+
+                Log.Error ("[Web] [SSE] Exception while trying to write:", true);
+                Log.Exception (e);
+
+                return ESseClientWriteResult.Error;
+            }
+        }
+
+        public void HandleKeepAlive () {
+            DateTime now = DateTime.Now;
+            if (!((now - lastMessageSent).TotalSeconds >= keepAliveIntervalSeconds)) {
+                return;
+            }
+
+            Write (keepAliveData, keepAliveData.Length);
+            lastMessageSent = now;
+        }
+        
+    }
+}
