Hi community,
so I am working on a simple tcp socket client that receives strings and why not JSON’s later on that I want to display inside a Textmesh object so that I scroll through the lines and letting the textmesh grow up t 20 lines.
The text is being served from a python script on the other side. I receive the data over my tcp class and it arrives inside my SocketResponse method but I can’t concatenate the steadily arriving strings into a single string to be displayed with the Textmesh.text value.
I tried the simple += concatenation, tried the Stringbuilder, tried the string List, I tried separate coroutines or separate Stringbuilder.Append() methods but absolutely no success. I tried so hard but there must be a problem upstream. It seems to work only for the first assignment. The strings get inside my scroller List but I just don’t get them to concatenate. What’s wrong? I really really hope you can help me here. Am I missing a type problem or a timing problem or what?
void OnGUI() {
if (myTCP.socketReady == false) {
if (GUILayout.Button ("Connect")) {
Debug.Log("Attempting to connect..");
myTCP.setupSocket();
signalsent = false;
}
}
if (myTCP.socketReady == true) {
SocketResponse ();
if (GUILayout.Button ("Disconnect")) {
Debug.Log("Disconnected");
myTCP.closeSocket();
}
if (!signalsent) {Debug.Log ("CONNECTED");signalsent = true;}
msgToServer = GUILayout.TextField(msgToServer);
if (GUILayout.Button ("Write to server", GUILayout.Height(30))) {
SendToServer(msgToServer);
}
}
}
And here is the method from the TCP class which defines the .readSocket():
//read message from server
public string readSocket() {
String result = "";
if (theStream != null && theStream.DataAvailable) {
Byte[] inStream = new Byte[mySocket.SendBufferSize];
theStream.Read(inStream, 0, inStream.Length);
result = System.Text.Encoding.UTF8.GetString(inStream);
}
return result;
}
Your SocketResponse is doing a lot of things! Looking only at the relevant parts for putting the socket response on the screen:
public void SocketResponse() {
string serverSays = myTCP.readSocket();
if (serverSays != "") {
string buffer = serverSays; //Why does this variable exist?
scroller.Add (buffer);
sb.Append(scroller.Last()); //Why is this not sb.Append(buffer)? Or sb.Append(serverSays)?
testMesh.text = sb.ToString();
}
}
That should work. As I’ve commented, you’re doing strange things, but appending to the string builder and putting the text in the text mesh is pretty straight forward.
I’m going to guess that it’s a wrapping issue. Try Debug.Logging the result of sb.ToString(), and also check the TextMesh in the inspector.
You’re right of course about SocketResponse, it’s just for debugging purposes. But in the screenshot you see that the problem, now with the simple List scroller through the StringBuilder sb, is still there. You can see at the bottom that the incoming serverSays has the string (btw why is it showing an o icon?) and scroller takes up the strings but sb processes incorrectly. It stops at taking up the very first string (“Subprocess running…”) but has a strangely large length for that string. The reason I’m saying this is that I tested the whole setup with passing a simple string line = “test” to scroller.Add(line) instead of passing serverSays and everything worked fine. Doing a sb.Append(serverSays) is giving the exact same result. Finally, I Debug.Logged for sb.ToString() but it’s the same result in the console and in the Inspector, no luck there. What’s next?
262144 is 2^18, apparently the socket’s buffer size or a multiple of it (I though it used to be 4kb or 8kb by default, not 256kb, so it probably appends several times), which you use in the following code of your read method:
followed by
which says “take all the bytes from inStream” and make a string out of it. So it’ll also convert all the other bytes that are probably just zeros.
You need to use the number of bytes that have been received, not sure which API you’re using but usually the Read method returns the number of bytes read.
So use another overload, passing inStream, 0 (unless you have other data in that buffer as well) and the number of bytes read. Only that part of the buffer should be converted to a string.
Fix the issue and report whats happening then.
And I probably wouldn’t allocate the huge buffer all the time, thats 256kb each time you receive something.
if (theStream != null && theStream.DataAvailable) {
Byte[] inStream = new Byte[mySocket.SendBufferSize];
theStream.Read(inStream, 0, 400);
result = System.Text.Encoding.UTF8.GetString(inStream);
result2 = result.Substring (0,100);
}
return result2;
I didn’t know how to get the number of actually sent bytes right now so I tried this. The StringBuilder’s length is now accordingly small but he still doesn’t want to concatenate the strings and stays with the first one. So still no luck.
Just to be complete, I also tried this more direct List to concatenated string approach which also - see line variable in the Locals - assigns only the first String… I don’t get it.
If you’re using the NetworkStream, you’ll get an integer as return value that indicates the number of bytes received via the stream when you call “Read(…)”.
For the concatenation issue, you probably only have to fix the reading operation.
But the things @Baste had mentioned are also worth to look at. You’re doing strange things, some of your variables and lines are not needed.
Regarding this line, which you haven’t fixed so far, please re-read my previous posts:
You have to fix that first, otherwise we can only guess what else is going wrong- and believe me, writing network code is a hell of work and discipline… Writing good and robust network code can be a real pain.
Take this code in order to check the difference between what you currently do, and what you should do instead:
var someString = "Suddoha";
var receiveBuffer = new byte[512];
// imagine that would be the networking part, which writes the received bytes into your buffer
var bytesReceived = System.Text.Encoding.UTF8.GetBytes(someString, 0, someString.Length, receiveBuffer, 0);
// that's what you do with the buffer
var decodedByteBuffer = System.Text.Encoding.UTF8.GetString(receiveBuffer);
Debug.Log(decodedByteBuffer.Length); // decoded length is 512
// that's what you should do with the buffer
var decodedString = System.Text.Encoding.UTF8.GetString(receiveBuffer, 0, bytesReceived);
Debug.Log(decodedString.Length); // decoded length is 7