I'm using SF Client API in Unity 3D and I have a problem with receiving XML-messages.
My client recieves XML-messages from the server to synchronize player's position like this:
Code: Select all
<msg t='xt'><body action='xtRes' r='-1'><![CDATA[<dataObj><var n='_cmd' t='s'>SendTransform</var><obj o='tr' t='a'><var n='z' t='n'>810.759399414062</var><var n='rz' t='n'>0</var><var n='rx' t='n'>0</var><var n='w' t='n'>0.831018149852753</var><var n='t' t='n'>1.22510742586314E12</var><var n='ry' t='n'>0.556245446205139</var><var n='y' t='n'>26.5978050231934</var><var n='x' t='n'>1376.97448730469</var></obj><var n='id' t='n'>1</var></dataObj>]]></body></msg>
But sometimes I receive from the server something like:
Code: Select all
<msg t='xt'><body action='xtRes' r='-1'><![CDATA[<dataObj><var n='_cmd' t='s'>SendTransform</var><
So the message is corrupted. It happens not very often, usually when one client are already in a room and another client joins this room, then the first client (which was already in the room) receives this broken message.
I think it's a bug. Let's look on the HandleSocketData method
Code: Select all
private void HandleSocketData(IAsyncResult ar)
{
int BytesRead;
try
{
// Finish asynchronous read into readBuffer and return number of bytes read.
BytesRead = socketConnection.GetStream().EndRead(ar);
if (BytesRead < 1)
{
// if no bytes were read server has close.
throw new Exception("No bytes could be read. Server connection disconnected");
}
// Add the received byte message to the messageBuffer, so we can cut up that one
messageBuffer += Encoding.ASCII.GetString(byteBuffer, 0, BytesRead);
// Cut up and handle each message separately
Regex findNumMessagesRegEx = new Regex("\0");
int numMessages = findNumMessagesRegEx.Matches(messageBuffer).Count;
if (numMessages != 0)
{
char[] delimChar = { '\0' };
string[] messages = messageBuffer.Split(delimChar);
for (int strCount = 0; strCount < messages.Length; strCount++)
{
// If this is the last string and its null, then we send all - nothing left for the buffer
// place rest in buffer else
if (strCount == messages.Length - 1)
{
if (messages[strCount].Length != 0)
{
messageBuffer = messages[strCount];
}
else
{
//Ignore last empty one
messageBuffer = "";
break;
}
}
HandleMessage(messages[strCount]);
}
}
else
{
// messageBuffer lives onto next socket data is received
}
// Start a new asynchronous read into readBuffer.
byteBuffer = new byte[READ_BUFFER_SIZE];
socketConnection.GetStream().BeginRead(byteBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(HandleSocketData), null);
}
catch (Exception e)
{
DebugMessage("Disconnect due to: " + e.ToString());
HandleSocketDisconnection();
}
}
When working with sockets in .NET it may happen that asynchronous delegate is being called earlier than all the sent data is read. Maybe you should transmit the length of incoming message first to let the client able to check if he has read all the bytes.
Anyway I think we should not handle disconnection on every exception here. Calling the HandleSocketDisconnection() method when we are not really disconnected from server leads to incorrect behaviour of the client-side. If we have received a corrupted message we can continue working. So I have added a try-catch block in HandleMessage method like this:
Code: Select all
private void HandleMessage(string msg)
{
if (msg != "ok") {
DebugMessage("[ RECEIVED ]: " + msg + ", (len: " + msg.Length + ")");
}
try {
string type = msg.Substring(0, 1);
if (type == MSG_XML)
{
XmlReceived(msg);
}
else if (type == MSG_STR)
{
StrReceived(msg);
}
else if (type == MSG_JSON)
{
JsonReceived(msg);
}
}
catch (Exception e) {
Debug.Log("Wrong message received! "+e.Message+" >> " +msg);
}
}
Now I'm using this as a workaround. I haven't tried to fix the socket problem yet, and I may be wrong concerning the reason of the bug. If I have time I will try to fix it, but I hope it will be fixed in the new version.
Thank you.