2

The client.cs in 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();
            }
        }
    }

The server.cs in Unity

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: Ok, I have updated both scripts. The server and client connects with no problems at all. I am able to see updated values when I check the readings in the server. My only issue right now is, delay. The client method is initiated every time the heart rate value is changed. When I set the valu to a label, it shows me a near real time change. But at the server side, the value takes 6 seconds to catchup with the new value (which by then has already sent another new value). Hope someone can clarify why.

UPDATE 4: Nevermind! I figured out the problem. It was due the TcpClient being initialized every time the method was run. This created the delay. I moved it up to the Forms_Load and commented out the s.Close() and client.Close(). The delay became much less, just near a second which is fine by me. Now though, I just need to find out when and how should I close the stream and TcpClient. I am trying the Environment.HasShutdownStarted to check when the application will close to shut the client and stream too but it is not working.

UPDATE 5: Alright, fixed the last issue by using the https://msdn.microsoft.com/en-us/library/system.windows.forms.application.applicationexit(v=vs.110).aspx! All Done!

ChaosEmperor93
  • 117
  • 3
  • 12

2 Answers2

1

I think it's the fact that you put all the server stuff in the Update. Which means it'll get called every frame. Which is a lot.

You should probably put all this in a separate method and call that from the client.

HoloLady
  • 1,041
  • 1
  • 12
  • 28
  • How would you call the method from the client? I thought the server should be first running then the client connects in order to send the data. Can you show me a reference to that? Thanks for the reply and sorry if this is a noob question, I am very new to sockets. – ChaosEmperor93 May 11 '15 at 08:48
  • I'm not that great with this myself, have you tried this? http://www.codeproject.com/Articles/10649/An-Introduction-to-Socket-Programming-in-NET-using I've not tested it, but it looks good. Why are you using a monobehaviour thing anyway? You could just not do that and call the server from a start method somewhere else. That way you could follow the tutorial closer and you won't be limited by the Update and Start stuff. – HoloLady May 11 '15 at 09:14
  • That is the exact tutorial I followed! I will try your advice. The reason I added them to the Update is because I thought they need to be called multiple times in order to keep receiving the data. I don't really know if it was right or wrong, it just made since in my head. – ChaosEmperor93 May 11 '15 at 12:45
  • Ok! I figured out how to use the threading. I guess I missed the creating new thread part in the tutorial. But now I am not receiving the data. The variable is empty for some reason. – ChaosEmperor93 May 11 '15 at 14:37
  • How are you setting the variable? Maybe try sending a simple string? – HoloLady May 11 '15 at 14:58
  • The variable is set in "string heartrate = sr.ReadLine ();" But when I use Debug.Log to check it, it turns to be empty. – ChaosEmperor93 May 11 '15 at 15:33
  • Ok, I figured out what was going on. I had an error that said the socket was null. It was a mistake in my server code where I initialized my stream before initializing the socket. Now I have a problem but no error. I can't seem to have the data being sent repeatedly. It's only being sent once and it does not update at all. I can't seem to figure out why. – ChaosEmperor93 May 11 '15 at 22:40
  • Okay, so it works once! That's progress! Now at least there's no bug in your sending code. In the tutorial they had a `while(true)` in their `Service()` could that be it? – HoloLady May 12 '15 at 06:41
  • Ok, I added it in the server but removed it from the client since I am already calling the method every time the value of the heart rate changes. It works as expected! The server reads all different variables! It all works with no issues. But now there is a delay in sending the updated value. It seems that the newest value is only sent after 6 seconds! I don't really know the issue for it. I will edit the whole post again with the newest scripts – ChaosEmperor93 May 12 '15 at 18:18
  • Nevermind! I figured out the problem. It was due the TcpClient being initialized every time the method was run. This created the delay. I moved it up to the Forms_Load and commented out the s.Close() and client.Close(). The delay became much less, just near a second which is fine by me. Now though, I just need to find out when and how should I close the stream and TcpClient. I am trying the Environment.HasShutdownStarted to check when the application will close to shut the client and stream too but it is not working. – ChaosEmperor93 May 12 '15 at 19:12
  • 1
    Alright, fixed the last issue by using the ! All Done! Thanks for your amazing help :D – ChaosEmperor93 May 12 '15 at 19:22
  • Yay! Glad you fixed it! I hardly did anything, go you! – HoloLady May 13 '15 at 06:58
1

You are starting and shutting down the streams at every frame. Move your s, sr and sw initializations to the Start method and use OnApplicationQuit for closing.

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

Doing so Unity will still hang as ReadLine is not asynchronous and will lock the execution until your socket receives data.

First two ways I can think of to go around this are:

  • using threads
  • using async callbacks (which I do in my UDP servers in Unity 3D). See this question: What is AsyncCallback?
Community
  • 1
  • 1
Steak Overflow
  • 7,041
  • 1
  • 37
  • 59