Running both server and client on one PC causes lag despite ping < 1 ms.

Started by
26 comments, last by Heelp 7 years, 6 months ago

Guys, I'm finally ready with the basic networking and clients can join freely to my server, and it's really cool, I tried with 3 clients simultaneously, and I still can't believe it's working. A few weeks ago I didn't know what IP, port and NAT mean, now I have my own server. :cool:

But the problem is that it starts lagging pretty hard. I checked the way I send the packets, everything seems fine, the only thing I send is 3D positions.

And I was wondering: can the reason be that I'm testing the networking on my own laptop?

The server receives gamestates from clients and then broadcasts all clients' positions every 75 milliseconds, this means that if I have 2 clients, the server sends only two glm::vec3 positions and it does it 13 times per second, and the clients just send "char" gamestates. Seems to me that the traffic is not so much. What do you think?

And when I go to cmd and ping 127.0.0.1, it says that ping is below 1ms, which is pretty cool, but then why is it lagging so hard?

I run the server and the client apps in small windows with 640x480 resolution and try to squeeze them so they can fit my 15.6 inch screen, which is not a problem at all, because I use RakNetGUID and it somehow knows what player is moved by what application although all the applications are run on one laptop and have the same IP.

Im sending stuff like this:

For clients: peer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, serverGUID, false );

For server: peer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true );

So nothing wrong with this part of the program.

If I decrease the update rate and change the sending time to 100 milliseconds, there is no lag at all, but the problem is that when I press "W", I need to wait a century until it moves forward. Is this my network limit, I really doubt it, I must be doing something wrong. :wacko:

NEED HELP :o

Advertisement
13 times a second is a bit slow, but not terrible; you might try tuning it to closer to 25 or 30 times a second and see if it feels better.


Generally speaking, testing over loopback addresses (like 127.0.0.1) is going to yield less latency than testing over an actual network connection. On modern OSes the traffic doesn't go through the network drivers and instead is just a copy of memory from one process to another, so it's about as fast as you can get.

It sounds like there is a problem in the way you transmit data but without more details it's hard to pinpoint.


For what it's worth I can run a complete set of game and infrastructure servers and a handful of full game clients on the same PC without hitting excessive latency issues.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

For what it's worth I can run a complete set of game and infrastructure servers and a handful of full game clients on the same PC without hitting excessive latency issues.

COME ON. I WANT THIS TOO. :o

It sounds like there is a problem in the way you transmit data but without more details it's hard to pinpoint.

Tell me all the details that you need. I would gladly provide them, of course. :rolleyes:

I will try to guess what you need in order to save us some time.

This is how I do the packet sending in my server. Done every 75 milliseconds. Timer starts counting when the server application is started.


void NetworkManager::serverSendPackets( vector<Player>& players )
{
    //Create a bitstream and broadcast all players' positions to every connected client
    RakNet::BitStream bsOut;
    bsOut.Write( ( RakNet::MessageID )ALL_PLAYERS_POSITIONS );

    for( int i = 0; i < players.size(); ++ i )
    {
        glm::vec3 vec = players[ i ].mainCam.getCurrentPosition();
        bsOut.Write( vec.x );
        bsOut.Write( vec.y );
        bsOut.Write( vec.z );
    }
    peer->Send( &bsOut, IMMEDIATE_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true );//Broadcast set to true.
}

And the client sending is absolutely lightweight, I just send a few RakNet::MessageIDs which are of type 'unsigned char'. Done every 75 milliseconds. The timer starts counting when the client application starts.


void NetworkManager::clientSendPackets( vector<Player>& players )
{
    RakNet::BitStream bsOut;

    if( myPlayerID >= 0 && players.size() > 0 )
    {
        if( players[ myPlayerID ].moveForward == true ) { bsOut.Write( ( RakNet::MessageID )PLAYER_MOVE_FORWARD ); }
        if( players[ myPlayerID ].moveBackwards == true ) { bsOut.Write( ( RakNet::MessageID )PLAYER_MOVE_BACKWARD ); }
        if( players[ myPlayerID ].moveLeft == true ) { bsOut.Write( ( RakNet::MessageID )PLAYER_MOVE_LEFT ); }
        if( players[ myPlayerID ].moveRight == true ) { bsOut.Write( ( RakNet::MessageID )PLAYER_MOVE_RIGHT ); }
    }

    if( bsOut.GetNumberOfBitsUsed() != 0 )
    {
        peer->Send( &bsOut, IMMEDIATE_PRIORITY, RELIABLE_ORDERED, 0, serverGUID, false );
    }
}

Hey, ApochPiQ, this may sound stupid but:

Can the problem happen because I use two different timers for client sending and for server sending. Should I synchronize the server and the client timers, to make sure they don't collide or something?

EDIT: or maybe this RELIABLE_ORDERED stuff slows something down?

EDIT No.2: ApochPiQ, I was randomly changing values I don't understand and I suddenly found the right one: I changed RELIABLE_ORDERED to UNRELIABLE_SEQUENCED, and IMMEDIATE_PRIORITY to MEDIUM_PRIORITY. I tested it, there is no lag now. But every 4-5 seconds I get a dropped packet and my game freezes for 50 ms, which sucks.

I did this because I was reading some programming tips in the RakNet website here:http://www.jenkinssoftware.com/raknet/manual/programmingtips.html

And I found this tip:

Position updates that are sent every 100 ms
Packetloss is generally only a few percent, so it wouldn't kill us to miss a packet. Even if we did the next packet arriving very soon would fix the problem. Unreliable sequenced would be very good here. Note however that this assumes we continually send packets. If we were to stop sending at some point the last packet(s) may never arrive which might be a problem.

I still can't figure out why IMMEDIATE_PRIORITY seems slower than MEDIUM_PRIORITY, and what is the difference between SEQUENCED and ORDERED, but it works fine. Do you have any ideas?

it starts lagging pretty hard

The very first step is to specify EXACTLY what you mean by this. These days, people say a game is "lagging" for several different reasons, each completely unrelated:

  • slow rendering frame rate (perhaps intermittent)
  • high latency between user input and visual feedback of this (which may not be related to networks)
  • wildly varying network latency
  • smooth but very delayed network latency

Probably the first thing to do - especially when testing on a local machine - is to put timestamps in outgoing messages, and to compare them with the local time when you receive a message. Exactly how long is each message taking? Does it vary by a lot, or a little? Does it correspond to the amount of lag that you feel?

I'm seeing a lot in your posts about how often you send data; but nothing about how often you receive it. Put some logging in the receive part of the program - let's see how often it is servicing that port. Receiving is passive so we often just assume it happens magically at the exact point where a message arrives, but obviously that can't be true.

If I decrease the update rate and change the sending time to 100 milliseconds, there is no lag at all, but the problem is that when I press "W", I need to wait a century until it moves forward.

This is why it's been said in previous threads that you need to simulate movement locally, not wait for a server reply before moving. But that's a separate issue to lag.

I agree with "Kylotan," "lagging" is not a sufficiently deep description to draw any conclusions from.

A few pieces of data you should log/plot from each of your server/clients:
- Average number of ticks/steps/frames per second, every 5 seconds or so
- Maximum time between successive ticks/steps/frames per 5 seconds or so
- Received and sent number of packets per second
- Received and sent client/server clock values (you should have each packet include the current local clock, and the last-received remote clock)

Making sure that the log starts each line with date/time and milliseconds-since-game-start, will make it easier to match the log files up later.

Another great tool for debugging is Wireshark. You should absolutely get a copy of Wireshark and install it (if you don't have it,) and use it to capture all the traffic to verify that the data and packets are what you think they are!
enum Bool { True, False, FileNotFound };
This is why it's been said in previous threads that you need to simulate movement locally, not wait for a server reply before moving. But that's a separate issue to lag.

Kylotan, but how am I supposed to simulate that movement locally, when I don't know where I'm gonna move. :huh:

Do you mean that I need to predict the movement on the client-side while waiting for a reply? Sounds too complicated. Can't I just wait for the server? I mean I just want to play over LAN, is there something simpler I can do?

In previous threads we were just talking about how interpolation for the rendering is done when the simulation is fixed-step ,but rendering isn't. And I solved this problem two weeks ago. I don't remember talking about predicting server positions. I will reread the previous threads, though, maybe someone else mentioned it, and I've missed it.

If you all can't understand what I'm doing, I guess I'm doing something really wrong.

But I will check on timestamps and see how they work in order to use them and try to debug something.

EDIT: Kylotan, I think I now understand what you've been saying. Did you mean that I can use the same extrapolation method I used when I was doing the variable-time rendering, but now, use it for networking?

Sounds ok, I just need a way to deal with delayed packets.

EDIT2: I will just drop them. I will post here if it worked, but maybe in a few days because I have a bunch of courseworks.( not that you need my posts, but.. :lol: )

If I remember correctly, you're writing an FPS, yes? In which case, the usual approach is to perform the movement on the client under the assumption that it will be accepted unmodified by the server. You don't need to extrapolate anything - all you're doing is not waiting for permission from the server first, just perform the action locally. Movement is usually very simple - just move the object along a vector - so there's no reason a client couldn't calculate that, including not moving through walls or obstacles, etc.

It gets more complicated when the server does reject the movement, as the server needs to tell the client what actually happened and the client then has to fix things up - but that can start off really simple (just snap the client back to where the server insists it should be) and improved later once you've got things working.

None of this has anything to do with your lag though. You should not be dropping delayed packets, because right now, on the LAN, you should never be getting delayed packets. By dropping them you're hiding a bug and leaving your code with 2 problems instead of 0.

You should not be dropping delayed packets, because right now, on the LAN, you should never be getting delayed packets.

Hmm, ok. It's very interesting why some stuff gets delayed. I mean I'm using 127.0.0.1 when sending, how faster than that... I will try to use wireshark and debug some stuff so I can maybe give you a bit more details.

Kylotan, hplus, thanks for the help.

EDIT: hplus, Wireshark seems pretty complicated because there is a lot of packet sending going on and I can't filter packets by processes or programs, how do you even use this stuff...

I can't filter packets by processes or programs, how do you even use this stuff


You can filter packets by protocol type (TCP, UDP, etc) and port number.
Presumably your game uses a known port, so filtering by that should be easy!
Then, each separate process will have a separate source port for the connection (in addition to the server port.)
enum Bool { True, False, FileNotFound };

I tried everything that comes to mind, but it still takes too much time for the packet to be received.

I timestamped the position packets that are sent from the server and the time varies from 22ms to 36ms and it's mostly 26-27ms. And I'm using 127.0.0.1 to connect. I think this is too much for two 3D vectors, am I right?

Server sending with timestamp:


void NetworkManager::serverSendPackets( vector<Player>& players )
{
    RakNet::Time timeStamp; //timestamping with raknet is really easy, I just get the time and write it onto a bitstream and that's it.
    timeStamp = RakNet::GetTime();

    RakNet::BitStream bsOut;

    if( players.size() > 0 ) 
    { 
      bsOut.Write( ( RakNet::MessageID )ALL_PLAYERS_POSITIONS );
      bsOut.Write( timeStamp );
    }

    for( int i = 0; i < players.size(); ++ i )
    {
        glm::vec3 vec = players[ i ].mainCam.getCurrentPosition();
        bsOut.Write( vec.x );
        bsOut.Write( vec.y );
        bsOut.Write( vec.z );
    }

    if( bsOut.GetNumberOfBitsUsed() != 0 )
    {
        peer->Send( &bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true );
    }
}

Client receiving:


void NetworkManager::clientReceivePackets( vector<Player>& players )
{
    RakNet::Time time;

    for( packet = peer->Receive(); packet; peer->DeallocatePacket( packet ), packet = peer->Receive() )
    {
        if( packet->data[ 0 ] == ALL_PLAYERS_POSITIONS )
        {
            RakNet::BitStream bsIn( packet->data, packet->length, false );
            bsIn.IgnoreBytes( sizeof( RakNet::MessageID ) );
            bsIn.Read( time );
            printf( "timestamp travel time = %d\n", RakNet::GetTime() - time ); // I receive the time and I print it.

            for( int i = 0; i < players.size(); ++ i )
            {
                bsIn.Read( playerPos.x );
                bsIn.Read( playerPos.y );
                bsIn.Read( playerPos.z );
                players[ i ].receivedPosition = playerPos;
            }
        }
    }
}

EDIT: Another weird problem. When I start the server, and then the client, sometimes the timestamping is 24-32ms as I told you earlier, but sometimes it gets to 52ms, 52ms, 51ms, 52ms and something like that. It depends on which time I start the client app.

This topic is closed to new replies.

Advertisement