Задержка Unity в отправке текущего значения при использовании сокетов


Клиент.cs в Visual Studio.

private void SendToServer(string HeartRate)
    {
        SetHRTest(HeartRate);
        try
        {
            s = client.GetStream();
            StreamReader sr = new StreamReader(s);
            StreamWriter sw = new StreamWriter(s);
            sw.AutoFlush = true;
            sw.WriteLine(HeartRate);
        }
        finally
        {
            if(Environment.HasShutdownStarted)
            {
                s.Close();
                client.Close();
            }
        }
    }

Сервер.cs в единстве

using UnityEngine;
using System.Collections;
using System.Net.Sockets;
using System.IO;
using System.Net;
using System.Threading;

public class Server {

public static TcpListener listener;
public static Socket soc;
public static NetworkStream s;
static public string CurrentHeartRate = "";
// Use this for initialization
public void StartService () {
    listener = new TcpListener (15579);
    listener.Start ();
    for(int i = 0;i < 1;i++){
         Thread t = new Thread(new ThreadStart(Service));
        t.Start();
        Debug.Log("3");
    }

}
void Service () {
    while (true) 
    {
        soc = listener.AcceptSocket ();
        s = new NetworkStream (soc);
        StreamReader sr = new StreamReader (s);
        StreamWriter sw = new StreamWriter (s);
        sw.AutoFlush = true;
        while(true)
        {
            string heartrate = sr.ReadLine ();
            if(heartrate != null)
            {
                CurrentHeartRate = heartrate;
                Debug.Log(heartrate);
            }
            else if (heartrate == null)
            {
                break;
            }
        }
        s.Close();
    }
}

void OnApplicationQuit()
{
    Debug.Log ("END");
    listener.Stop ();
    s.Close();
    soc.Close();
}

}

UPDATE 3: Ок, я обновил оба скрипта. Сервер и клиент соединяются без проблем вообще. Я могу видеть обновленные значения, когда проверяю показания на сервере. Моя единственная проблема сейчас-это задержка. Метод клиента запускается каждый раз, когда изменяется значение частоты сердечных сокращений. Когда я устанавливаю valu на метку, она показывает мне изменение почти в реальном времени. Но на стороне сервера, значение требуется 6 секунд, чтобы догнать новое значение (которое к тому времени уже отправило другое новое значение). Надеюсь, кто-нибудь объяснит почему.

Обновление 4: неважно! Я понял, в чем проблема. Это было связано с тем, что TcpClient инициализировался каждый раз при запуске метода. Это создало задержку. Я переместил его в Forms_Load и прокомментировал s. Close () и клиент.Закрывать(). Задержка стала намного меньше, всего около секунды, что меня вполне устраивает. Но сейчас мне просто нужно выяснить, когда и как должен ли я закрыть поток и TcpClient. Я пробую окружающую среду.HasShutdownStarted, чтобы проверить, когда приложение закроется, чтобы закрыть клиента и поток тоже, но он не работает.

Обновление 5: хорошо, исправлена последняя проблема с помощью https://msdn.microsoft.com/en-us/library/system.windows.forms.application.applicationexit(v=vs. 110).aspxВсе готово!

2 2

2 ответа:

Я думаю, дело в том, что вы поместили все серверные материалы в обновление. А это значит, что его будут вызывать каждый кадр. А это очень много.

Вероятно, вам следует поместить все это в отдельный метод и вызвать его из клиента.

Вы запускаете и выключаете потоки на каждом кадре. Переместите ваши s, sr и sw инициализируют метод Start и используют OnApplicationQuit для закрытия.

void OnApplicationQuit()
{
   s.Close();
   soc.Close();
}

При этомUnity все равно будет висеть , поскольку ReadLine не является асинхронным и блокирует выполнение до тех пор, пока сокет не получит данные.

Первые два способа, которые я могу придумать, чтобы обойти это:

  • использование потоков
  • использование асинхронных обратных вызовов (что я и делаю на своих UDP серверах в Unity 3D). Смотрите этот вопрос: Что такое AsyncCallback?