using UnityEngine; | |
using UnityEngine.Networking; | |
using System; | |
using System.IO; | |
using System.Net; | |
using System.Threading; | |
public class UnityHttpListener : MonoBehaviour | |
{ | |
private HttpListener listener; | |
private Thread listenerThread; | |
void Start () | |
{ | |
listener = new HttpListener (); | |
listener.Prefixes.Add ("http://localhost:4444/"); | |
listener.Prefixes.Add ("http://127.0.0.1:4444/"); | |
listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous; | |
listener.Start (); | |
listenerThread = new Thread (startListener); | |
listenerThread.Start (); | |
Debug.Log ("Server Started"); | |
} | |
void Update () | |
{ | |
} | |
private void startListener () | |
{ | |
while (true) { | |
var result = listener.BeginGetContext (ListenerCallback, listener); | |
result.AsyncWaitHandle.WaitOne (); | |
} | |
} | |
private void ListenerCallback (IAsyncResult result) | |
{ | |
var context = listener.EndGetContext (result); | |
Debug.Log ("Method: " + context.Request.HttpMethod); | |
Debug.Log ("LocalUrl: " + context.Request.Url.LocalPath); | |
if (context.Request.QueryString.AllKeys.Length > 0) | |
foreach (var key in context.Request.QueryString.AllKeys) { | |
Debug.Log ("Key: " + key + ", Value: " + context.Request.QueryString.GetValues (key) [0]); | |
} | |
if (context.Request.HttpMethod == "POST") { | |
Thread.Sleep (1000); | |
var data_text = new StreamReader (context.Request.InputStream, | |
context.Request.ContentEncoding).ReadToEnd (); | |
Debug.Log (data_text); | |
} | |
context.Response.Close (); | |
} | |
} |
I found this solution for me now - just added to Start method:
EditorApplication.playModeStateChanged += delegate(PlayModeStateChange state)
{
if (state == PlayModeStateChange.ExitingPlayMode)
{
listener.Stop();
listenerThread.Abort();
Debug.Log("Server stoped");
}
};
But recommend to add checking of listening to StartListener method, cause it throws an error at finish playmode:
while (true)
{
if (listener.IsListening)
{
var result = listener.BeginGetContext(ListenerCallback, listener);
result.AsyncWaitHandle.WaitOne();
}
}
Would it not be better or possible to do this with a coroutine instead of an entirely separate System.Thread?
using UnityEngine;
using UnityEngine.Networking;
using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
public class UnityHttpListener : MonoBehaviour
{
private HttpListener listener;
void Start()
{
listener = new HttpListener();
listener.Prefixes.Add("http://localhost:4444/");
listener.Prefixes.Add("http://127.0.0.1:4444/");
listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
listener.Start();
StartCoroutine("startListenerCoroutine");
Debug.Log("Server Started");
}
private System.Collections.IEnumerator startListenerCoroutine()
{
while(listener.IsListening)
{
Task<HttpListenerContext> task = listener.GetContextAsync();
yield return new WaitUntil(() => task.IsCompleted);
ProcessRequest(task.Result);
}
}
private void ProcessRequest(HttpListenerContext context)
{
Debug.Log("Method: " + context.Request.HttpMethod);
Debug.Log("LocalUrl: " + context.Request.Url.LocalPath);
if (context.Request.QueryString.AllKeys.Length > 0) {
foreach (var key in context.Request.QueryString.AllKeys) {
Debug.Log ("Key: " + key + ", Value: " + context.Request.QueryString.GetValues(key)[0]);
}
}
if (context.Request.HttpMethod == "POST") {
var data_text = new StreamReader (context.Request.InputStream, context.Request.ContentEncoding).ReadToEnd();
Debug.Log (data_text);
}
context.Response.StatusCode = 200;
context.Response.StatusCode = "OK";
context.Response.Close ();
}
void OnApplicationQuit() {
listener.Stop();
Debug.Log("Server stoped");
}
}
https://gist.github.com/PikaChokeMe/7604fa19596ea6f66019898a948a8dd2
I will say that I don't know the performance implications of this over the dedicated thread; however.
ThatOtherVRGuy Check out the IPManager class in this thread on StackExchange. It will grab the IP address for you.
https://stackoverflow.com/questions/51975799/how-to-get-ip-address-of-device-in-unity-2018
You can also bind to ip address 127.0.0.1 (localhost) or simply or use a wildcard (though it's not always a good thing to bind to all IP addresses on a system.)
I would also like to comment on the topic of treads vs. coroutines. Coroutines are great for in-game things that you can guarantee will happen quickly and/or can be sliced neatly into sections to spread across frames. The nature of HTTP, however, cannot guarantee any sort of timing and from my experience should generally be done in a separate thread. This, of course, does depend a lot on what you're doing with it.
To get arround that problem I randomize the port on Awake. you can send an event with the new port used so that whatever script who needs it can grab the event.