Message passing between Master Server and client
by Vishal Vohra · in Torque Game Engine · 07/29/2005 (6:36 am) · 17 replies
I am trying to pass a message between masterserver and client, Master Server is a seperata projet just like TNL's Master Server and Master client project.
It gives the following error "Unpack did not match Pack for event of class RPC_MasterServerInterface _c2mQueryServers ".
What may be the possibility why it is giving this error, please help.
It gives the following error "Unpack did not match Pack for event of class RPC_MasterServerInterface _c2mQueryServers ".
What may be the possibility why it is giving this error, please help.
#2
Mine implementation is almost same as sepearate MasterServer and client example of TNL. previously it was giving the same error for some other rpc function, i have comment that and it gives the error for another function, what can be the probem, any idea
07/29/2005 (10:49 am)
We tried using the same files MasterInterface.h and .cpp on MasterServer and Client, and the function signatures also match properly but still the error persist.Mine implementation is almost same as sepearate MasterServer and client example of TNL. previously it was giving the same error for some other rpc function, i have comment that and it gives the error for another function, what can be the probem, any idea
#3
07/29/2005 (12:58 pm)
Have you done a clean rebuild on both?
#4
we have MasterInterface.h and .cpp on both and I have written two extra RPC functions c2mrpcMessageClientToServer and m2cMessageServerToClient for testing the message passing between the two. I have override the c2mrpcMessageClientToServer on MasterServerConnection.cpp and nothing else and calling this function from the client's MasterServerConnection.cpp at onConnectionEstablished, I have not override any other function which are mentioned in MasterInterface.h and .cpp
08/01/2005 (6:16 am)
Yes, I have done the rebuild on both.we have MasterInterface.h and .cpp on both and I have written two extra RPC functions c2mrpcMessageClientToServer and m2cMessageServerToClient for testing the message passing between the two. I have override the c2mrpcMessageClientToServer on MasterServerConnection.cpp and nothing else and calling this function from the client's MasterServerConnection.cpp at onConnectionEstablished, I have not override any other function which are mentioned in MasterInterface.h and .cpp
#5
08/01/2005 (6:35 pm)
What are the actual parameter lists? Are you sending vectors larger than 1kb of data, or ByteBuffers > 1023 bytes?
#6
TNL_DECLARE_RPC(c2mrpcMessageClientToServer, (StringPtr szString));
TNL_DECLARE_RPC(m2crpcMessageServerToClient, (StringPtr szString));
besides this MasterInterface.h and .cpp is as same as mentioned in the example of MasterServer and Client, no other rpc function is defined anywhere else or override, except only above two.
08/03/2005 (6:00 am)
This is the actual data I am trying to send c2mrpcMessageClientToServer("Master Srv");TNL_DECLARE_RPC(c2mrpcMessageClientToServer, (StringPtr szString));
TNL_DECLARE_RPC(m2crpcMessageServerToClient, (StringPtr szString));
besides this MasterInterface.h and .cpp is as same as mentioned in the example of MasterServer and Client, no other rpc function is defined anywhere else or override, except only above two.
#7
08/03/2005 (11:27 pm)
How long a string are you sending?
#8
08/04/2005 (7:07 am)
I ensure that the message does not exceed size 32 before sending the data. The length is always below 32. But yet the error occurs. Even while sending with sample string "Master Srv" by calling function c2mrpcMessageClientToServer("Master Srv"); the error message pops out. Please help.
#9
I am sending a heavy amount of traffic using the net object pack/unpack update mechanisms.
I send a guid as a string across as one of the parameters.
After a random time during play, the client will assert giving a message saying unpack update did not match packupdate for multiplayernetobject, received XXX bytes, expected YYY.
The problem is, the expected size (in bits) matches none of the combinations of data i send, so looking for a problem on my side is made more tricky.
I am using the latest version in CVS. If I use the rpc mechanisms, I dont send the guid as a string it works perfectly. This leads me to think its a problem with either your string packing, or your packing in general for netobject sending/receiving.
If I am sending large amounts of data that overrun the send recv buffers occasionally, then I gt this problem, if I reduce the amount of data i am sending, the problem dissapears.
The game runs fine most of the time, and in all situations using the same netobjects and data, its only when it needs to limit the sending due to the buffer sizes that problems arise.
As it runs fine when data bandwidth is within the limits, I can only assume that the data send/recv matches and has no missalignment of bits etc etc.
Luckily for me, I have taken the packupdate packets and am now using the rpc/event mech for those, which dodges this problem for this title, however, its not very reasuring knowing this problem is there.
08/04/2005 (10:04 am)
I have also got problems similar to this.I am sending a heavy amount of traffic using the net object pack/unpack update mechanisms.
I send a guid as a string across as one of the parameters.
After a random time during play, the client will assert giving a message saying unpack update did not match packupdate for multiplayernetobject, received XXX bytes, expected YYY.
The problem is, the expected size (in bits) matches none of the combinations of data i send, so looking for a problem on my side is made more tricky.
I am using the latest version in CVS. If I use the rpc mechanisms, I dont send the guid as a string it works perfectly. This leads me to think its a problem with either your string packing, or your packing in general for netobject sending/receiving.
If I am sending large amounts of data that overrun the send recv buffers occasionally, then I gt this problem, if I reduce the amount of data i am sending, the problem dissapears.
The game runs fine most of the time, and in all situations using the same netobjects and data, its only when it needs to limit the sending due to the buffer sizes that problems arise.
As it runs fine when data bandwidth is within the limits, I can only assume that the data send/recv matches and has no missalignment of bits etc etc.
Luckily for me, I have taken the packupdate packets and am now using the rpc/event mech for those, which dodges this problem for this title, however, its not very reasuring knowing this problem is there.
#10
Vishal,
Can you post your full header (or e-mail it)? Are you using the same header file in both builds?
M,
You are aware that strings are Huffman encoded? The byte length of the string has no strict relationship to its contents (ie, each byte gets a variable length encoding).
If you overrun packetsize, things will break. TNL is not meant as a bulk data transport, so it assumes that you'll design your events to fit in the available packet space (ie, small events, not monolithic ones). You will need to limit all of your packUpdate/NetEvent stuff to fit.
08/05/2005 (12:11 am)
Have both of you tried setting mDebugObjectSizes on the connection parameters to be true? It will enable a lot of extra debugging and sanity checking that might reveal exactly what the problem is. Vishal,
Can you post your full header (or e-mail it)? Are you using the same header file in both builds?
M,
You are aware that strings are Huffman encoded? The byte length of the string has no strict relationship to its contents (ie, each byte gets a variable length encoding).
If you overrun packetsize, things will break. TNL is not meant as a bulk data transport, so it assumes that you'll design your events to fit in the available packet space (ie, small events, not monolithic ones). You will need to limit all of your packUpdate/NetEvent stuff to fit.
#11
#ifndef _MASTERINTERFACE_H_
#define _MASTERINTERFACE_H_
#include "tnlEventConnection.h"
#include "tnlRPC.h"
using namespace TNL;
namespace ABCD
{
// Useful string constants...
static const char *MasterNoSuchHost = "No Such Host";
static const char *MasterRequestTimedOut = "Timed Out";
enum MasterConstants {
ConnectRequestTimeout = 30000,
IPMessageAddressCount = 30,
GameMissionTypesPerPacket = 20,
};
class MasterServerInterface : public EventConnection
{
protected:
public:
enum {
MasterServerInterfaceVersion = 1,
};
TNL_DECLARE_RPC(c2mrpcMessageClientToServer, (StringPtr szString));
TNL_DECLARE_RPC(m2crpcMessageServerToClient, (StringPtr szString));
TNL_DECLARE_RPC(c2mQueryGameTypes, (U32 queryId));
TNL_DECLARE_RPC(m2cQueryGameTypesResponse, (U32 queryId, Vector gameTypes, Vector missionTypes));
TNL_DECLARE_RPC(c2mQueryServers, (U32 queryId, U32 regionMask,
U32 minPlayers, U32 maxPlayers, U32 infoFlags,
U32 maxBots, U32 minCPUSpeed, StringTableEntry gameType, StringTableEntry missionType));
TNL_DECLARE_RPC(m2cQueryServersResponse, (U32 queryId, Vector ipList));
TNL_DECLARE_RPC(c2mRequestArrangedConnection, (U32 requestId,
IPAddress remoteAddress, IPAddress internalAddress,
ByteBufferPtr connectionParameters));
TNL_DECLARE_RPC(m2cClientRequestedArrangedConnection, (U32 requestId, Vector possibleAddresses,
ByteBufferPtr connectionParameters));
TNL_DECLARE_RPC(c2mAcceptArrangedConnection, (U32 requestId, IPAddress internalAddress, ByteBufferPtr connectionData));
TNL_DECLARE_RPC(c2mRejectArrangedConnection, (U32 requestId, ByteBufferPtr rejectData));
TNL_DECLARE_RPC(m2cArrangedConnectionAccepted, (U32 requestId, Vector possibleAddresses, ByteBufferPtr connectionData));
TNL_DECLARE_RPC(m2cArrangedConnectionRejected, (U32 requestId, ByteBufferPtr rejectData));
TNL_DECLARE_RPC(c2mUpdateServerStatus, (
StringTableEntry gameType, StringTableEntry missionType,
U32 botCount, U32 playerCount, U32 maxPlayers, U32 infoFlags));
TNL_DECLARE_RPC(m2cSetMOTD, (StringPtr motdString));
};
};
#endif
08/05/2005 (6:12 am)
/*Here is the full header, yes I am using the same header file in both builds*/#ifndef _MASTERINTERFACE_H_
#define _MASTERINTERFACE_H_
#include "tnlEventConnection.h"
#include "tnlRPC.h"
using namespace TNL;
namespace ABCD
{
// Useful string constants...
static const char *MasterNoSuchHost = "No Such Host";
static const char *MasterRequestTimedOut = "Timed Out";
enum MasterConstants {
ConnectRequestTimeout = 30000,
IPMessageAddressCount = 30,
GameMissionTypesPerPacket = 20,
};
class MasterServerInterface : public EventConnection
{
protected:
public:
enum {
MasterServerInterfaceVersion = 1,
};
TNL_DECLARE_RPC(c2mrpcMessageClientToServer, (StringPtr szString));
TNL_DECLARE_RPC(m2crpcMessageServerToClient, (StringPtr szString));
TNL_DECLARE_RPC(c2mQueryGameTypes, (U32 queryId));
TNL_DECLARE_RPC(m2cQueryGameTypesResponse, (U32 queryId, Vector
TNL_DECLARE_RPC(c2mQueryServers, (U32 queryId, U32 regionMask,
U32 minPlayers, U32 maxPlayers, U32 infoFlags,
U32 maxBots, U32 minCPUSpeed, StringTableEntry gameType, StringTableEntry missionType));
TNL_DECLARE_RPC(m2cQueryServersResponse, (U32 queryId, Vector
TNL_DECLARE_RPC(c2mRequestArrangedConnection, (U32 requestId,
IPAddress remoteAddress, IPAddress internalAddress,
ByteBufferPtr connectionParameters));
TNL_DECLARE_RPC(m2cClientRequestedArrangedConnection, (U32 requestId, Vector
ByteBufferPtr connectionParameters));
TNL_DECLARE_RPC(c2mAcceptArrangedConnection, (U32 requestId, IPAddress internalAddress, ByteBufferPtr connectionData));
TNL_DECLARE_RPC(c2mRejectArrangedConnection, (U32 requestId, ByteBufferPtr rejectData));
TNL_DECLARE_RPC(m2cArrangedConnectionAccepted, (U32 requestId, Vector
TNL_DECLARE_RPC(m2cArrangedConnectionRejected, (U32 requestId, ByteBufferPtr rejectData));
TNL_DECLARE_RPC(c2mUpdateServerStatus, (
StringTableEntry gameType, StringTableEntry missionType,
U32 botCount, U32 playerCount, U32 maxPlayers, U32 infoFlags));
TNL_DECLARE_RPC(m2cSetMOTD, (StringPtr motdString));
};
};
#endif
#12
I understand TNL is not a bulk data transport, although I said I am shifting a lot of data, that may have been missleading. What I meant was that our game (FPS) has a large number of entities (net objects) in it. At times the culling of sends (ie I only send data about other net objects to clients that are near enough to be affected by them) does not work if all objects are in close proximity. The packets I am sending are quite small individually, the largest individual update packet being ~300bytes, although these are only send every couple of seconds or so as these regard NPC's.
Are you suggesting that we have to monitor the amount of data sent and limit that ourselves? I was under the impression that TNL does that internally.
The assert I was talking about happens (client side only) if I try to send too much data to them, ie too many small update packets.
At this time I have no spare time to run through TNL and see whats happening (as I can get satisfactory results using netevents instead of using the packupdate mechanism).
Yes, I see the huffman process involved with the strings, however, I would have thought the size of the string post process would not be massively different to the origional, especially as the string I mention is < 16 characters.
I cannot suggest what the problem might be at the moment, but as it only happens when the collective data size of all my update packets exceeds the buffer sizes I have to start there.
One oddity is that when you have a packet that does not match the written order of an expected packet you get the "Invalid Packet" error (which subsequently causes the connection to be closed). I do not get those with this problem.
cheers,
M
08/05/2005 (8:46 am)
Ben,I understand TNL is not a bulk data transport, although I said I am shifting a lot of data, that may have been missleading. What I meant was that our game (FPS) has a large number of entities (net objects) in it. At times the culling of sends (ie I only send data about other net objects to clients that are near enough to be affected by them) does not work if all objects are in close proximity. The packets I am sending are quite small individually, the largest individual update packet being ~300bytes, although these are only send every couple of seconds or so as these regard NPC's.
Are you suggesting that we have to monitor the amount of data sent and limit that ourselves? I was under the impression that TNL does that internally.
The assert I was talking about happens (client side only) if I try to send too much data to them, ie too many small update packets.
At this time I have no spare time to run through TNL and see whats happening (as I can get satisfactory results using netevents instead of using the packupdate mechanism).
Yes, I see the huffman process involved with the strings, however, I would have thought the size of the string post process would not be massively different to the origional, especially as the string I mention is < 16 characters.
I cannot suggest what the problem might be at the moment, but as it only happens when the collective data size of all my update packets exceeds the buffer sizes I have to start there.
One oddity is that when you have a packet that does not match the written order of an expected packet you get the "Invalid Packet" error (which subsequently causes the connection to be closed). I do not get those with this problem.
cheers,
M
#13
Do your IMPLEMENT_RPC macros match as well? What do you get if you have the debug flag I mentioned set?
M,
I'm very confused by your nomenclature. Are you manually sending your own packets (bypassing TNL's low level packet protocol)? Or are you referring by "packet" to an individual update written to an actual UDP packet that is then sent over the wire? Your comment, "I cannot suggest what the problem might be at the moment, but as it only happens when the collective data size of all my update packets exceeds the buffer sizes I have to start there." leads me to believe that you're perhaps trying to send too much data in one go, which will cause TNL to assert (there's no convenient recovery path if you exceed the maximum packet size you've set). As long as your updates are smaller than the nominal packet size and the max, you'll be OK.
The Huffman process can conceivably give you compression ratios of 50% or better (or potentially expand the string beyond its original length!), so for some value of "massive" you can have massively different sizes.
For both of you,
The debug flag will definitely help identify bugs, if any - otherwise I've little recourse but to shrug and say regretfully that you're probably not using the system as it was intended. :)
08/05/2005 (9:55 am)
Vishal,Do your IMPLEMENT_RPC macros match as well? What do you get if you have the debug flag I mentioned set?
M,
I'm very confused by your nomenclature. Are you manually sending your own packets (bypassing TNL's low level packet protocol)? Or are you referring by "packet" to an individual update written to an actual UDP packet that is then sent over the wire? Your comment, "I cannot suggest what the problem might be at the moment, but as it only happens when the collective data size of all my update packets exceeds the buffer sizes I have to start there." leads me to believe that you're perhaps trying to send too much data in one go, which will cause TNL to assert (there's no convenient recovery path if you exceed the maximum packet size you've set). As long as your updates are smaller than the nominal packet size and the max, you'll be OK.
The Huffman process can conceivably give you compression ratios of 50% or better (or potentially expand the string beyond its original length!), so for some value of "massive" you can have massively different sizes.
For both of you,
The debug flag will definitely help identify bugs, if any - otherwise I've little recourse but to shrug and say regretfully that you're probably not using the system as it was intended. :)
#14
I am only using your methods to transmit. When I say "packet" i mean a call through "pack/unpackUndate.
It is my understanding that TNL packages all messages into a single buffer that gets sent to the client (thereby reducing the number of UDP sends per client avoiding multiple 26byte header overheads).
When you say i am trying to send too much data in one go, do you mean too much in one packet (packupdate call) or exceeding the single send buffer?
I was under the impression TNL handled overruns into the send buffer by winding back if a packupdate exceeds the available size of the send buffer and waits until the next network update to send it (or just drops it).
I fail to see how sending packets through TNL only using your pack/unpack update mechanisms for small, frequent updated, non-guaranteed data is using it in a way that is not intended. All I am sending is pos, angle, velocity, firing, crouching etc.
08/05/2005 (11:02 am)
Ben,I am only using your methods to transmit. When I say "packet" i mean a call through "pack/unpackUndate.
It is my understanding that TNL packages all messages into a single buffer that gets sent to the client (thereby reducing the number of UDP sends per client avoiding multiple 26byte header overheads).
When you say i am trying to send too much data in one go, do you mean too much in one packet (packupdate call) or exceeding the single send buffer?
I was under the impression TNL handled overruns into the send buffer by winding back if a packupdate exceeds the available size of the send buffer and waits until the next network update to send it (or just drops it).
I fail to see how sending packets through TNL only using your pack/unpack update mechanisms for small, frequent updated, non-guaranteed data is using it in a way that is not intended. All I am sending is pos, angle, velocity, firing, crouching etc.
#15
TNL_IMPLEMENT_RPC_OVERRIDE(MasterServerConnection, c2mQueryGameTypes, (U32 queryId))
TNL_IMPLEMENT_RPC_OVERRIDE(MasterServerConnection, c2mrpcMessageClientToServer , ( StringPtr Vis) )
Is it necessary to OVERRIDE every function ?
1. the IMPLEMENT_RPC are in MasterServerInterface.cpp
2. I am also doing this in MasterServerConnection.h
TNL_DECLARE_RPC_OVERRIDE(c2mQueryGameTypes, (U32 queryId));
TNL_DECLARE_RPC_OVERRIDE(c2mrpcMessageClientToServer, ( StringPtr Vis));
3. and TNL_IMPLEMENT_RPC_OVERRIDE in MasterServerConnection.cpp
08/05/2005 (12:58 pm)
Yes the IMPLEMENT_RPC macros do match as well, but I have OVERRIDE only these two:TNL_IMPLEMENT_RPC_OVERRIDE(MasterServerConnection, c2mQueryGameTypes, (U32 queryId))
TNL_IMPLEMENT_RPC_OVERRIDE(MasterServerConnection, c2mrpcMessageClientToServer , ( StringPtr Vis) )
Is it necessary to OVERRIDE every function ?
1. the IMPLEMENT_RPC are in MasterServerInterface.cpp
2. I am also doing this in MasterServerConnection.h
TNL_DECLARE_RPC_OVERRIDE(c2mQueryGameTypes, (U32 queryId));
TNL_DECLARE_RPC_OVERRIDE(c2mrpcMessageClientToServer, ( StringPtr Vis));
3. and TNL_IMPLEMENT_RPC_OVERRIDE in MasterServerConnection.cpp
#16
What are you sending in an object update in an FPS that takes up 300 bytes???
Are you using the journaling functionality of TNL? You might want to check journaling out, as it makes catching these network issues MUCH easier -- you get a deterministic replay you can step through over and over in the debugger.
Let me know if any of this helps.
08/06/2005 (3:00 am)
M, have you recently updated your version of TNL? There were some bugs fixed in the late spring dealing with packet overrun that could be complicit.What are you sending in an object update in an FPS that takes up 300 bytes???
Are you using the journaling functionality of TNL? You might want to check journaling out, as it makes catching these network issues MUCH easier -- you get a deterministic replay you can step through over and over in the debugger.
Let me know if any of this helps.
#17
I previously had overrun problems, but one of your guys fixed that and added it to the reposotory some months ago (May time I think). Unfortunatly, we are using tomcrypt with another area of the game, and that is built using a later version than your tnl uses. It is also compiled with conflicting precompiler options, so one lib wont suffice for both. This is a bit frustrating, but I have modified your tomcrypt lib so it does not share function/struct names with the later required tomcrypt lib. This all works but means I cannot readilly do an update from your CVS, I have to check each changed file and apply the changes manually. It only takes half an hour or so. I did a full update last week.
300 bytes :P yes, its a bit excessive. Its actually about 190 bytes at the moment, and these are only required to transmit every couple of seconds (they are NPC's), so its not as bad as it sounds. This will eventually be cut back to a more appropriate size (<40 bytes) very soon. I think the problem was I was not only running out of bandwidth buffer space, but I was running out of the send buffer space, which caused problems. If I create a very large send buffer, the problem goes away (although it starts getting choppy, but like I said, these issues are going to be gone when I start optimising it all).
I will use the journaling feature soon and let you know how it goes.
cheers Mark.
M
08/08/2005 (9:44 am)
Mark,I previously had overrun problems, but one of your guys fixed that and added it to the reposotory some months ago (May time I think). Unfortunatly, we are using tomcrypt with another area of the game, and that is built using a later version than your tnl uses. It is also compiled with conflicting precompiler options, so one lib wont suffice for both. This is a bit frustrating, but I have modified your tomcrypt lib so it does not share function/struct names with the later required tomcrypt lib. This all works but means I cannot readilly do an update from your CVS, I have to check each changed file and apply the changes manually. It only takes half an hour or so. I did a full update last week.
300 bytes :P yes, its a bit excessive. Its actually about 190 bytes at the moment, and these are only required to transmit every couple of seconds (they are NPC's), so its not as bad as it sounds. This will eventually be cut back to a more appropriate size (<40 bytes) very soon. I think the problem was I was not only running out of bandwidth buffer space, but I was running out of the send buffer space, which caused problems. If I create a very large send buffer, the problem goes away (although it starts getting choppy, but like I said, these issues are going to be gone when I start optimising it all).
I will use the journaling feature soon and let you know how it goes.
cheers Mark.
M
Associate Ben Garney