I have coded a server-client (two programs) structure which does work properly... only when TCP is used. My idea was to use TCP to do text chat transfer (udp is unreliable), but to use UDP for the game packets (yes it is some sort of action game with 30 fps, so I need UDP).
However, when I established a connection with TCP in my client process, I start sending UDP packets to and receive from the server program. The client uses non-blocking sockets, UDP and TCP in a single thread. No multi-threading here, I do not really like that idea if you can implement it in one process too.
However, the problem is that is seems as if the UDP packets take more than 5 seconds to arrive from client to server: they do arrive in most cases (I repeat sendto until I received a packet from the server indicating successful UDP transmission) but it takes far too long. The only problem I can imagine in the structure is the fact that I use TCP and UDP at the same time.
Note that I probably use different ports (sendto lets the OS bind to a port) and I ran the client and server on the same machine. I read somewhere that every process can only send one packet at a time; if that is the case, could that be the culprit of these negative experiences with UDP?
Code of server sending a game frame to client.
void SendGameData()
{
unsigned char i, a, c;
CBytes cont;
CLoops(i, 0, app.clients)
{
if (client[i].step != 4)
continue;
// Send basic data
tempbuf[0] = 0;
tempbuf[1] = game.players;
tempbuf[2] = client[i].player;
core.CSendTo(net.udp, &client[i].udpaddr, tempbuf, 3);
// Send player positions
CLoops(a, 0, game.players)
{
tempbuf[0] = a + 1;
c = 1;
strcpy(tempbuf + c, player[a]->name);
c += strlen(player[a]->name) + 1;
cont.value = player[a]->obj.pos.x;
tempbuf[c++] = cont.bytes[0];
tempbuf[c++] = cont.bytes[1];
tempbuf[c++] = cont.bytes[2];
tempbuf[c++] = cont.bytes[3];
cont.value = player[a]->obj.pos.y;
tempbuf[c++] = cont.bytes[0];
tempbuf[c++] = cont.bytes[1];
tempbuf[c++] = cont.bytes[2];
tempbuf[c++] = cont.bytes[3];
cont.value = player[a]->dir.x;
tempbuf[c++] = cont.bytes[0];
tempbuf[c++] = cont.bytes[1];
tempbuf[c++] = cont.bytes[2];
tempbuf[c++] = cont.bytes[3];
cont.value = player[a]->dir.y;
tempbuf[c++] = cont.bytes[0];
tempbuf[c++] = cont.bytes[1];
tempbuf[c++] = cont.bytes[2];
tempbuf[c++] = cont.bytes[3];
cont.value = player[a]->angle;
tempbuf[c++] = cont.bytes[0];
tempbuf[c++] = cont.bytes[1];
tempbuf[c++] = cont.bytes[2];
tempbuf[c++] = cont.bytes[3];
tempbuf[c++] = player[a]->defeated;
tempbuf[c++] = player[a]->health;
/*player[game.players]->normalspeed = true;
if (gmode[gdata.modeprofile].mode == M_MATCH && !gmode[gdata.modeprofile].timeorstock)
player[game.players]->lives = gmode[gdata.modeprofile].stock;
player[game.players]->score = 0;
player[game.players]->wait = 0;
player[game.players]->ammo[WP_HMG] = 0;
player[game.players]->ammo[WP_CANNON] = 10;
player[game.players]->ammo[WP_AUTO] = 15;
player[game.players]->ammo[WP_ART] = 0;
player[game.players]->ammo[WP_LMG] = 50;
player[game.players]->ammo[WP_MINI] = 0;
player[game.players]->ammo[WP_AT] = 0;
player[game.players]->weapon = WP_AUTO;
player[game.players]->doubledamage = 0;
player[game.players]->speedboost = 0;*/
core.CSendTo(net.udp, &client[i].udpaddr, tempbuf, c);
}
}
}
Client code of receiving the game state from server within a frame time limit:
int r;
char k;
CBytes cont;
memset(&cont, 0, sizeof(CBytes));
unsigned char c, count = 0;
CByte8u timez = core.CGetTime() + mswait;
while (true)
{
r = core.CRecvFrom(net.udp, NULL, net.tempbuf, NET_BUFSIZE);
if (r > 0)
{
if (net.tempbuf[0] == 0) // Basics
{
k = net.tempbuf[1] - (char)game.players;
if (k > 0)
{
CLoops(c, 0, (unsigned char)k)
SpawnPlayer();
}
else if (k < 0)
{
CLoops(c, 0, (unsigned char)k)
DespawnPlayer(game.players - 1);
}
game.you = net.tempbuf[2];
count |= 0x01;
}
else
{
c = 0;
k = net.tempbuf[0] - 1;
strcpy(player[k]->name, net.tempbuf);
c += strlen(player[k]->name) + 1;
cont.bytes[0] = net.tempbuf[c++];
cont.bytes[1] = net.tempbuf[c++];
cont.bytes[2] = net.tempbuf[c++];
cont.bytes[3] = net.tempbuf[c++];
player[k]->obj.pos.x = cont.value;
cont.bytes[0] = net.tempbuf[c++];
cont.bytes[1] = net.tempbuf[c++];
cont.bytes[2] = net.tempbuf[c++];
cont.bytes[3] = net.tempbuf[c++];
player[k]->obj.pos.y = cont.value;
cont.bytes[0] = net.tempbuf[c++];
cont.bytes[1] = net.tempbuf[c++];
cont.bytes[2] = net.tempbuf[c++];
cont.bytes[3] = net.tempbuf[c++];
player[k]->dir.x = cont.value;
cont.bytes[0] = net.tempbuf[c++];
cont.bytes[1] = net.tempbuf[c++];
cont.bytes[2] = net.tempbuf[c++];
cont.bytes[3] = net.tempbuf[c++];
player[k]->dir.y = cont.value;
cont.bytes[0] = net.tempbuf[c++];
cont.bytes[1] = net.tempbuf[c++];
cont.bytes[2] = net.tempbuf[c++];
cont.bytes[3] = net.tempbuf[c++];
player[k]->angle = cont.value;
player[k]->defeated = (bool)net.tempbuf[c++];
player[k]->health = net.tempbuf[c];
player[k]->weapon = WP_AUTO;
count |= 0x02;
}
}
if (count == 3)
break;
else if (r == -2)
return false;
else if (core.CGetTime() > timez)
{
strcpy(core.inerr, "UDP session timed out.");
return false;
}
}
return true;
These processes happen simultaneously on two separate processes, every frame takes about 20 ms.
r == -2
check in the receiving code: I assume thatcore.CRecvFrom
have its own error codes that it returns? Because the standardrecvfrom
will not return-2
specifically. – Some programmer dude