简体   繁体   中英

TCP and UDP interference

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.

You may like route_io , it is c/c++ based library, it make udp/tcp/http all in one single instance. You just get the source and example to do whatever you want for your project. Simple Example

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "route_io.h"

void init_instance(void *arg);
void read_handler(rio_request_t *req);

void init_instance(void *arg) {
  printf("%s\n", "start instance");
}

void read_handler(rio_request_t *req) {
  printf("preparing echo back %.*s\n", (int) (req->in_buff->end - req->in_buff->start), req->in_buff->start);
  rio_write_output_buffer_l(req, req->in_buff->start, (req->in_buff->end - req->in_buff->start));
}

void on_conn_close_handler(rio_request_t *req) {
  printf("%s\n", "connection closing");
}

int main(void) {

  rio_instance_t * instance = rio_create_routing_instance(24, NULL, NULL);
  rio_add_udp_fd(instance, 12345/*port*/, read_handler, on_conn_close_handler);
  rio_add_tcp_fd(instance, 3232/*port*/, read_handler, 64, on_conn_close_handler);

  rio_start(instance);

  return 0;
}

Such a behavior of your app is usual. Unfortunately, it is due to many factors.

First of all, I advise you to check whether the packet is "actually" sent to the destination. Network packet analyzer such as Wireshark will be a help. If you don't have more computer, try using a virtual machine by VirtualBox or Hyper-V, or call bind("xxx.xxx.xxx.xxx") where xxx.xxx.xxx.xxx is your computer IP address. Wireshark will show you whether the packets are sent immediately or delayed.

Unless you are sending more than 500MB/sec thru loopback UDP socket, The cause may be in your program itself, not network something. Here is an example.

Assuming that packets are really sent too late, then your client app may have the cause. Check if your app is written like this:

FrameMove()
{
    a = send_queue.peek_first();
    r = udpSocket.sendTo(dest, a);
    if (r == success)
    {
        send_queue.pop_first();
    }

    ... (other routines)
}

This should be fixed like this:

FrameMove()
{
    while(!send_queue.is_empty())
    {
        a = send_queue.peek_first();
        r = udpSocket.sendTo(dest, a);
        if (r == success)
        {
            send_queue.pop_first();
        }
        else if (r == would_block)
        {
            break;
        }
    }
    ... (other routines)
}

UDP sometimes affects TCP performance and stability, but the vice versa is rare.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM