0

I'm connecting to a server that talks in a JSON protocol. It sends each bit of information as a JSON object. Here are three examples.

{"from":"SERVER","code":"SERVER_OK"}
{"from":"SERVER","code":"CHAT_JOIN","data":{"room":"Lobby"}}
{"from":"SERVER","code":"PING","data":{"time":1405901428001}}

My C# code looks like this.

  void Start () {
    clientSocket = new TcpClient();
    clientSocket.Connect("127.0.0.1", 5000);
    serverStream = clientSocket.GetStream();
    serverStream.BeginRead(buffer, 0, buffer.Length, ReadComplete, buffer);
  }

  void ReadComplete (IAsyncResult iar) {
    buffer = (byte[])iar.AsyncState;
    int bytesAvailable = serverStream.EndRead(iar);
    string data = System.Text.Encoding.UTF8.GetString(buffer);
    Array.Clear(buffer, 0, 4096);

    serverStream.BeginRead(buffer, 0, buffer.Length, ReadComplete, buffer);

    Debug.Log(data);
  }

My debug log looks like this:

{"from":"SERVER","code":"SERVER_OK"}{"from":"SERVER","code":"CHAT_JOIN","data":{"room":"Lobby"}}
{"from":"SERVER","code":"PING","data":{"time":1405901428001}}
{"from":"SERVER","code":"PING","data":{"time":1405901433001}}
{"from":"SERVER","code":"PING","data":{"time":1405901438004}}

It looks like I can receive more than one JSON object at a time in each ReadComplete. I also assume I could receive a partial JSON object as well. What do I need to do to be able to process a single JSON object at a time? I'm guessing I have to concatenate each received chunk of data to a string and the chop off the front of it each object one at a time. I just have no idea how to go about doing that.

2 Answers 2

2

I ended up moving into a Thread and processing the stream one byte at a time looking for the JSON object boundaries. For each on I try to parse it and add it a Queue for the parent thread to process.

So far this seems to work without causing any threading issues with the rest of my application and has been working well with the overall performance for my needs.

  // The network thread listening to the server
  private void NetworkThread () {
    Debug.Log("Connecting to server...");
    clientSocket = new TcpClient();
    clientSocket.Connect("127.0.0.1", 5000);
    stream = clientSocket.GetStream();

    int braces = 0;
    bool inQ = false;
    char lastB = ' ';
    while (!stopThread) {
      char b = (char)stream.ReadByte();
      if (b < 0)
        return;

      buffer.Append((char)b);
      if (b == '"' && lastB != '\\') {
        inQ = !inQ;
      }
      else if (b == '{' && !inQ) {
        braces += 1;
      }
      else if (b == '}' && !inQ) {
        braces -= 1;
      }
      lastB = (char)b;
      if (braces == 0) {
        try {
          JSONNode packet = JSONNode.Parse(buffer.ToString());
          buffer = new StringBuilder();
          lock (lockQueue) {
            packetQueue.Enqueue(packet);
          }
        } catch (Exception e) {
        }
      }
    }
  }
Sign up to request clarification or add additional context in comments.

Comments

1

Instat of manually reciving the data use Streamreader and it's .ReadLine() method. It looks like the server sends line for line, so it should not be a problem to read response for response.

3 Comments

Would I loose the async nature that BeginRead and ReadComplete provide?
I tried this, ReadLine() won't work the server isn't sending linebreaks after each JSON object
My idea is to try to split at each {} with Regex.Split(value, "{}"). You check then every entry with JSON.NET for valid JSON. If it passes, you found one entry, if not save it to a variable and then go on reciving. Put the saved string in front of the recived and split, check and so on. I think you should be able to build a working routine from this. To bad the server isn't sending linebreaks. ( ._ .)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.