Detecting Bandwidth and Network Statistics

At least currently, network bandwidth can be a difficult problem to work around. The majority of people on the internet today still have "low speed" modem-based connections. Even those with high-speed or broadband connections (which are steadily increasing) have a maximum upload and download speed. The goal of the network programmer is to ensure that there is little enough information going through the wire so as to not take up all available bandwidth, while at the same time ensuring that enough data is passed through to maintain the information needed.

The application you are writing for has a lot of effect on this as well. For example, if you are writing the server code for a massive online multiplayer game, then you would expect that server to have a fat pipe, with tons of available bandwidth. It's expected to maintain connections with thousands of clients simultaneously, each of them constantly sending data to the server. Plus, the server itself must send out data to each client quite often as well. Tuning the data throughput for this application is much different than, say, for the client of this server. The client only sends a small amount of data, and only to one spot, the server. It also only receives a small amount of data from that same server.

DirectPlay's API is generic enough to allow you to connect the information you need in order to make decisions on how much data you are passing across clients. If you wanted to get an idea of the current stats of your session, you could call the GetConnectionInformation method on your session. For a server or peer object, you must pass in the player id for the player you wish to receive this information on; the client will return the information about its connection with the server. Let's look at a sample output of this data:

 Connection information: PacketsDropped: 0 BytesDropped: 0 PacketsRetried: 0 BytesRetried: 0 PacketsSentNonGuaranteed: 1 BytesSentNonGuaranteed: 0 PacketsSentGuaranteed: 99 BytesSentGuaranteed: 1344 PeakThroughputBps: 116 ThroughputBps: 80 RoundTripLatencyMs: 4 MessagesReceived: 79 PacketsReceivedNonGuaranteed: 0 BytesReceivedNonGuaranteed: 0 PacketsReceivedGuaranteed: 79 BytesReceivedGuaranteed: 1836 MessagesTimedOutLowPriority: 0 MessagesTransmittedLowPriority: 0 MessagesTimedOutNormalPriority: 0 MessagesTransmittedNormalPriority: 99 MessagesTimedOutHighPriority: 0 MessagesTransmittedHighPriority: 1 

As you can see, there is a wealth of information here. You can easily see the number of packets (and bytes) that were dropped (only non-guaranteed packets would be dropped).

You can see the number of packets (and bytes) that were retried (guaranteed packets that failed to reach the destination). The number of packets (and bytes) you send, both guaranteed and non-guaranteed, is included as well.

The next few members are really where this information is useful. You can see the peak throughput of the pipe in bytes per second, as well as the average throughput. You could use this information to determine whether you are sending too much data, or possibly not enough. For example, if the average throughput was 100 bytes per second, and you're sending 30K of data per second, you are killing the bandwidth. However, if the opposite were the case, you'd have plenty of extra bandwidth to fill with extra information.

Another useful piece of information you can see here is the average round trip latency. This is the approximate time it takes any packet to be received by the remote system and returned to you. Long round trip latencies are another indication that you may be oversaturating the bandwidth of either your connection or possibly the remote systems.

We round out this information by seeing the number of guaranteed and non-guaranteed packets (and bytes) we have received from the remote system. Finally, we get an indication of the number of messages we have had time out or have transmitted for each of the three priority levels (normal, low, and high).

This is all well and good, but in reality some period of time needs to pass in order to make any sound judgments on the current state of the network. A way to determine the state of the network at any given time would help eliminate this statistic tracking.

DirectPlay will not send messages to a remote computer faster than it can process them. If it detects that the remote computer isn't responding fast enough, it will queue the messages on the sender, and not send them until a more appropriate time. During this time, depending on the send options, the packets may be coalesced or timed out. If you are receiving a lot of time outs in your send complete event handler, you will know the remote system is having a tough time keeping up with the data you are sending.

You can also check the amount of data in the send queue directly by calling the GetSendQueueInformation method. Much like the GetConnectionInformation method, the server and peer objects expect the player id of the user who will check the send queue, while the client will not expect this id. In each of these objects, two integer out parameters will be returned from the call. The first is the number of messages currently waiting in the send queue. The second is the number of combined bytes these messages take up. You may control the priority of the data you are checking by passing in the appropriate member of the GetSendQueueInformationFlags enumeration as well. If you detect the send queue filling up, it's a very good indication that you need to send less data to this client.

You may also use the properties returned from the SendComplete event to help in determining potential lag. You can find the total amount of time it took to send the packet, as well as the first frame's round-trip time.

The most important thing to remember when trying to tune your network performance is to eliminate unnecessary data being passed across the wire. Don't send strings unless it's necessary. Never send a Boolean variable if you have more than one, and most of the time don't send even one. Rather than sending four Boolean variables, send one byte that is bit-masked for the various Boolean constants. For example, let's say you have four Booleans:

 private bool IsRunning = true; private bool IsMale = false; private bool IsWarrior = true; private bool IsGhost = false; 

Now, say that you need to send each of these every frame, and so you add them all to your network packet. Just for these 4 variables, your network packet is now 16 bytes. Obviously that's highly inefficient, and we can get it down to a single byte. Look at this:

 private const byte IsRunning = 0x1; private const byte IsMale = 0x2; private const byte IsWarrior = 0x4; private const byte IsGhost = 0x8; private byte SendData = IsRunning | IsWarrior; 

Now, the SendData member is only a single byte and holds the same information that our 4 Boolean variables did. A single byte can hold 8 Boolean values (saving 31 bytes in the process). If you need more than 8, move up to the short type, which can hold up to 16 Boolean variables (saving 62 bytes). You can go up to the long type, which will hold a whopping 64 Boolean variables (and save a whopping 252 bytes).

Always use the smallest data type possible to minify the amount of traffic you will need to generate. If you don't need a full 32-bit integer, don't use the int type; switch to the short type. The more data you can get in the smaller packets, the more available network bandwidth you will have.



Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net