Unity Web Request and Server Side Events

Ok, I’m working on a project an need a game server. I’ve looked over LOTS of possibilities including Websockets, Telnet, etc. Server Side Events would easily do what I need and would require the least amount of effort creating this server. Here’s the problem. I have this code and it works:

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Collections.Generic;
using UnityEngine;

public class SSEvents : MonoBehaviour
{

    public static List<string> Queue = new List<string>(1024);
    public static Stream SSEStream;
    public static UTF8Encoding encoder = new UTF8Encoding();
    public static byte[] buffer = new byte[2048];

    public class SSEvent
    {
        public string Name { get; set; }
        public string Data { get; set; }
    }

    // Start is called before the first frame update
    void Start()
    {
        OpenSSEStream("https://www.myserver.com/SSEvents.php");
    }

    public static void OpenSSEStream(string url)
    {
        var request = WebRequest.Create(new Uri(url));
        ((HttpWebRequest)request).AllowReadStreamBuffering = false;
        var response = request.GetResponse();
        SSEStream = response.GetResponseStream();
    }

    void Update()
    {
        if (SSEStream.CanRead)
        {
            int len = SSEStream.Read(buffer, 0, 2048);
            if (len > 0)
            {
                var text = encoder.GetString(buffer, 0, len);
                Debug.Log(text);
            }
        }
    }
}

And I have this PHP code on the server:

<?php

date_default_timezone_set("America/New_York");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");

$counter = rand(1, 10);
while (true) {
  // Every second, send a "ping" event.
 
  echo "event: ping\n";
  $curDate = date(DATE_ISO8601);
  echo 'data: {"time": "' . $curDate . '"}';
  echo "\n\n";
 
  // Send a simple message at random intervals.
 
  $counter--;
 
  if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 10);
  }
 
  ob_end_flush();
  flush();

  // Break the loop if the client aborted the connection (closed the page)

  if ( connection_aborted() ) break;

  sleep(1);
}

?>

The problem is, because I have to keep polling the stream in the update, it turns the game into a slug. Anyone have any better code to do SSE in Unity???

*edit Did some testing and wow. Just the act of getting the length of the buffer takes almost a full second.

Thanks

If you really need instant updates each frame, I’d use a real time network solution instead of your web request system. Otherwise I’d try to move checking the stream to another thread. But even keeping it in Update here, do you really need to check the stream every frame? If you checked it once a second instead of once a frame, would it really impact your game other than improving performance?

1 Like

Yea, I just set up a timer to check every 30 seconds and every time it does this:

int len = SSEStream.Read(buffer, 0, 2048);

The game freezes for about a second.

Not sure how to move this to a thread. I’m not much of a C# programmer so threading still boggles me.

And even if it is threaded, is UWR blocking or non-blocking???

Most likely this function will keep reading until it accumulates 2048 bytes in the buffer, unless the stream ends first (it doesn’t end first). And given that your server periodically sends small pieces of data, this will take a while.

Try using ReadAsync instead.
https://docs.microsoft.com/en-us/dotnet/api/system.io.stream.readasync?view=netcore-3.1#System_IO_Stream_ReadAsync_System_Byte___System_Int32_System_Int32_