0

I've been researching and came to the conclusion that using StreamWriter.WriteLine is not the best idea. However, using StreamWriter.Write and prefixing the actual message bytes size and sending it from the client to the server so the server will know where to start reading and where to stop reading.

Here is working code I have so far:

public void Send(string header, Dictionary<string, string> data)
{
    new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true;
        if (stream.CanRead)
        {
            socketReady = true;
        }

        if (!socketReady)
        {
            return;
        }
        JsonData SendData = new JsonData();
        SendData.header = "1x" + header;
        foreach (var item in data)
        {
            SendData.data.Add(item.Key.ToString(), item.Value.ToString());
        }
        SendData.connectionId = connectionId;

        string json = JsonConvert.SerializeObject(SendData);
        byte[] JsonToBytes = Encoding.ASCII.GetBytes(json);
        byte[] lengthArray = BitConverter.ToInt32(JsonToBytes, 0);
        stream.Write(lengthArray, 0, lengthArray.Length);
        stream.Write(JsonToBytes, 0, JsonToBytes.Length);
        stream.Flush();



        Debug.Log("Client World:" + json);
    }).Start();
}

This is how I send the data to the server. As you see I'm using writer.WriteLine(json); I know that I need to change that first to calculate the size of the message in bytes and send it as a prefix.

Here is how i read the data at the server:

        //Console.WriteLine("Call");
        if (!serverStarted)
        {
            return;
        }

        foreach (ServerClient c in clients.ToList())
        {
            // Is the client still connected?
            if (!IsConnected(c.tcp))
            {
                c.tcp.Close();
                disconnectList.Add(c);
                Console.WriteLine(c.connectionId + " has disconnected.");
                CharacterLogout(c.connectionId);
                continue;
                //Console.WriteLine("Check for connection?\n");
            }
            else
            {                 
                // Check for message from Client.
                NetworkStream s = c.tcp.GetStream();
                if (s.DataAvailable)
                {
                    string data = c.streamReader.ReadLine();

                    if (data != null)
                    {
                        OnIncomingData(c, data);
                    }

                }
                //continue;
            }
        }

        for (int i = 0; i < disconnectList.Count - 1; i++)
        {
            clients.Remove(disconnectList[i]);
            disconnectList.RemoveAt(i);
        }

As you see I'm using c.streamReader.ReadLine(); which is reading the Line as a delimiter. I don't want that. I need to change it to check the message size in bytes, read it and then send it to OnIncomingData(c, data); as an actual message without the bytes prefix.

However, I don't know how to calculate the actual message size in the client, form it and send it. I'm also not aware how to proceed it in the reading in the server.

Can you please review my code and make edits to my code so it will work in this manner and I can understand how it works?

Venelin
  • 2,905
  • 7
  • 53
  • 117
  • Use `BitConverter.ToInt32(byteToSend, 0);` to get the size of the array then send that over the network. On the client, use `BitConverter.GetBytes(receivedByteLength)` to get the size of the data. You can then use that value to read from server until you reach that length. See [this](https://stackoverflow.com/questions/42717713/unity-live-video-streaming/42727918#42727918) post for more info. Read from A to E. – Programmer Dec 06 '17 at 11:27
  • Thank you for your comment. Is it possible to make it as an answer and applying some edits to the code i have provided because what you said is not very clear to me. – Venelin Dec 06 '17 at 13:10
  • @Programmer my message now is a string. Does that mean i have to split my message as an array and send every row if the array and then reassemble it at the server when it reaches the size limit ? – Venelin Dec 07 '17 at 11:22
  • You don't split anything. Read that link I provided. I never mentioned anything about splitting. If that link is too hard to understand, see [this](https://stackoverflow.com/questions/11740952/c-sharp-problems-with-sending-receiving-size-of-bytes-sockets) which is short. That question has a send/receive code that describes what you need to do even better. – Programmer Dec 07 '17 at 12:55
  • I have updated my `Send` function. Does that seems correct to you ? – Venelin Dec 07 '17 at 13:05
  • "I've been researching and came to the conclusion that using StreamWriter.WriteLine is not the best idea." That's a very confusing way to start without explaining what you're trying to achieve and why you don't want to use `StreamWriter.WriteLine`. Please clarify the question. – Jon Skeet Dec 07 '17 at 13:13
  • Is `.WriteLine` good enough message delimiter ? I've been told it's not. – Venelin Dec 07 '17 at 13:16
  • Sorry, there was a mistake in my first comment. Switch the sentences around.On the server, `BitConverter.GetBytes` is used to send the total bytes followed by the actual bytes. On the CLIENT, `BitConverter.ToInt32` is used to retrieve the size of expected data then loop on a receive with that size until it's complete. Now see the link from my last comment for example. That's it. @JonSkeet Shout-out to Jon Skeet! – Programmer Dec 07 '17 at 13:50
  • Good enough for what? It's good enough to be read by `StreamReader.ReadLine`, but it's not good if your content could include line breaks naturally. If you're concerned about which line break is used, you can set that with the `NewLine` property. It sounds like your concern may not be with `StreamReader`/`StreamWriter` itself, but with using a delimiter rather than a per-message length prefix. That's a perfectly reasonable concern, but it's worth distinguishing between the two. If you're happy to write a new-line, then `StreamWriter.WriteLine` is absolutely fine. – Jon Skeet Dec 07 '17 at 14:01

0 Answers0