0

I'm using Unity 5.5.4.

I have create a TCP Server and a Client listener.

Here is how i connect to the server on the Client:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net.Sockets;
using System.IO;
using System;
using System.Text.RegularExpressions;
using UnityEngine.SceneManagement;
using Newtonsoft.Json;
using System.Linq;
using System.Threading;

public class ClientWorldServer : MonoBehaviour {

    public bool socketReady;
    public static TcpClient socket;
    public static NetworkStream stream;
    public static StreamWriter writer;
    public static StreamReader reader;

public void ConnectToWorldServer()
{
    if (socketReady)
    {
        return;
    }
    //Default host and port values;
    string host = "127.0.0.1";
    int port = 8080;

    //ClientLoginServer ClientLoginServer = new ClientLoginServer();


    try
    {

        socket = new TcpClient(host, port);
        stream = socket.GetStream();
        socket.NoDelay = true;
        writer = new StreamWriter(stream);
        reader = new StreamReader(stream);
        socketReady = true;
        //Preserve the connection to worldserver thrue scenes
        DontDestroyOnLoad(worldserverConnection);
    }
    catch (Exception e)
    {
        Debug.Log("Socket error : " + e.Message);
    }

}

}

Inside the same ClientWorldServer class here is how i check for available data:

// Update is called once per frame
void Update () {

        if (socketReady)
        {
            if (stream.DataAvailable)
            {
                string data = reader.ReadLine();
                if (data != null)
                {
                    OnIncomingData(data);

                }                
            }
        }

}

For those who are not familiar with Unity void Update() is called once per frame. It's pretty much like endless while loop.

Here is my OnIncomingData function:

   private void OnIncomingData(string data)
    {

        new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;

            JsonData json = JsonConvert.DeserializeObject<JsonData>(data);


            string prefix = json.header.Substring(0, 2);

            if (prefix != "0x")
            {
                Debug.Log("Unknown packet: " + data + "\n");
            }
            else
            {

                string header = json.header.Substring(2);
                int conId = json.connectionId;
                //Debug.Log("Header:" + header);
                switch (header)
                {
                    default:
                        Debug.Log("Unknown packet: " + data + "\n");
                        break;
                    case "000":
                        Debug.Log("Empty header received: " + json.header + "\n");
                        break;
                    case "001":

                        if(connectionId == 0)
                        {
                            connectionId = conId;
                            Debug.Log("Connection ID: " + connectionId + "\n");
                        }
                        break;
                    case "004":
                        DisplayCharacterSelects(json.data, connectionId);
                        break;
                    case "005":
                        PlayerSpawner playerSpawner = new PlayerSpawner();
                        playerSpawner.SpawnPlayer(json.data, conId);
                        break;
                    case "006":
                        PlayerSpawner OnliePlayersSpawner = new PlayerSpawner();
                        OnliePlayersSpawner.SpawnOnlinePlayers(json.data);
                        break;
                    case "007":
                        CharacterLogout(json.data);
                        break;
                    case "008":
                        Character character = new Character();
                        character.updateCharacterPosition(json.data, conId);
                        break;
                    case "009":
                        Character characterR = new Character();
                        characterR.updateCharacterRotation(json.data, conId);
                        break;
                }
                Debug.Log("World Server: " + data);
            }
        }).Start();
    }

On the checks that i've made i can assure you that the server is not slowing the process of sending data. The client is somehow slowing at reading. It's important to say that i'm sending players position when they move to the server and then server responds back to all the clients connected notifying them that some player has changes it's position. That means that a lot of requests are made per 1 second.

Maybe i'm not taking the best approach or i have a rookie mistake but this is my first touch with TCP.

Do you see any reason why processing of the data in many requests can be slowed at the client and if so how can i fix it?

Venelin
  • 2,905
  • 7
  • 53
  • 117
  • `string data = reader.ReadLine();` should be moved to another Thread. Reading, writing, listening to ports and connecting to server should all be done in another thread. This will solve your issue – Programmer Nov 22 '17 at 07:41
  • But the whole `OnIncomingData` function is in separate thread. – Venelin Nov 22 '17 at 07:43
  • So what's a problem exactly, how is it manifested? Lags on client side, delay in position updates? – Evk Nov 22 '17 at 07:44
  • On clients side i can see when the data is read. On the server i check when it stops to send data. I see that the server stops sending data but like after 1,2 or even 3 seconds the client stops reading and respectively changes position of the player. Which is kind of lag. – Venelin Nov 22 '17 at 07:46
  • Look closely at your server code. You have `string data = reader.ReadLine();` in the `Update` function the `OnIncomingData(data);`. That `string data = reader.ReadLine();` before the `OnIncomingData(data);` in running on the main thread. Finally, do not start a new Thread each time you check `stream.DataAvailable`. Instead, open connection then start a new Thread and put all your read/send code there in a `while(true)` loop so that this thread will run forever. – Programmer Nov 22 '17 at 07:49
  • How often Update is called? How big is message rate (10 per second, 100)? – Evk Nov 22 '17 at 07:49
  • @Programmer can you make a complete answer with your suggestion and modifying the code as it will resolve the problem ? – Venelin Nov 22 '17 at 07:52
  • @Evk Update is called once per frame. You can imagine how many times it's called :D – Venelin Nov 22 '17 at 07:52
  • See the duplicate for the `while` loop in another Thread. It has a complete functional TCP. If you ever want to call into the main Thread or use Unity API from that `while` loop that is running in another Thread, see [this](https://stackoverflow.com/questions/41330771/use-unity-api-from-another-thread-or-call-a-function-in-the-main-thread) post I made for a wrapper to do that. – Programmer Nov 22 '17 at 07:55
  • Here you mean: https://stackoverflow.com/questions/36526332/unity3d-c-sharp-plugin-to-act-as-a-socket-server ? – Venelin Nov 22 '17 at 08:08
  • Also what is the difference between the ordinary thread and SocketThread? Does Unity not work well with `Thread` ? – Venelin Nov 22 '17 at 08:17
  • @Programmer i have applied everything you said as well the trick for reaching functions into the Unity's main thread. I can really test right now for the "Lag" bug but it seems to be okey. Thank you very much! – Venelin Nov 22 '17 at 09:21
  • You are welcome! – Programmer Nov 22 '17 at 09:26
  • @Programmer everything works perfect! One more question. Is it good idea to create a new thread on the server for every connection it has ? – Venelin Nov 22 '17 at 09:42
  • You have to create new thread for each one or use the Async functions. The network class has async function for each function that blocks. For example `ConnectAsync`..That's really up to you to decide. Also you can mix the Thread ansync to make to separate your network program with your main game code. Just create one thread for your network stuff then use the async functions inside that new thread. It's really up to you. – Programmer Nov 22 '17 at 09:51
  • Hello again @Programmer can you please take a look at this question: https://stackoverflow.com/questions/47672684/c-unity-convert-streamwriter-writeline-to-streamwriter-write-and-message-byte – Venelin Dec 06 '17 at 11:15

0 Answers0