Hello everyone!
Alright, Iâm making a multiplayer action game, you know, where people
connect to a server and kill each other.
But I want to know how a good client-server should look like⌠Iâve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clientsâŚ
Or should I do something else? Thanks!
If you really want to do it properly you would use
the equivalent of âphase lockingâ. Thatâs like driving a car.
Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.
You cannot show the correct position at all times due to lag.
This is not an artifact either â it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is ⌠eg blur vision or
something so the player can take the lag into account.
[of course when you see cows teleporting you know your
ping is down ⌠but by then youâre dead :]On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:
Hello everyone!
Alright, Iâm making a multiplayer action game, you know, where people
connect to a server and kill each other.
But I want to know how a good client-server should look like⌠Iâve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clientsâŚ
Or should I do something else? Thanks!
â
John Skaller
Felix, successor to C++: http://felix.sf.net
Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:
Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player Aâs client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the ârunâ animation), Player Bâs position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player Aâs client now adjusts, using an âeasingâ animation to go from
the ârunâ animation to the âstandingâ animation.
Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a âmassively multi playerâ game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered âinstancingâ of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.
One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, Iâm not referring to OS specific
packet scheduling but scheduling built into your application.).
Hope that helps you on your way.
-Elden Armbrust
skaller wrote:> On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:
Hello everyone!
Alright, Iâm making a multiplayer action game, you know, where people
connect to a server and kill each other.
But I want to know how a good client-server should look like⌠Iâve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clientsâŚ
Or should I do something else? Thanks!If you really want to do it properly you would use
the equivalent of âphase lockingâ. Thatâs like driving a car.Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.You cannot show the correct position at all times due to lag.
This is not an artifact either â it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is ⌠eg blur vision or
something so the player can take the lag into account.[of course when you see cows teleporting you know your
ping is down ⌠but by then youâre dead :]
Elden Armbrust wrote:
Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player Aâs client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the ârunâ animation), Player Bâs position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player Aâs client now adjusts, using an âeasingâ animation to go from
the ârunâ animation to the âstandingâ animation.Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a âmassively multi playerâ game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered âinstancingâ of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, Iâm not referring to OS specific
packet scheduling but scheduling built into your application.).Hope that helps you on your way.
-Elden Armbrustskaller wrote:
Hello everyone!
Alright, Iâm making a multiplayer action game, you know, where people
connect to a server and kill each other.
But I want to know how a good client-server should look like⌠Iâve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clientsâŚ
Or should I do something else? Thanks!If you really want to do it properly you would use
the equivalent of âphase lockingâ. Thatâs like driving a car.Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.You cannot show the correct position at all times due to lag.
This is not an artifact either â it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is ⌠eg blur vision or
something so the player can take the lag into account.[of course when you see cows teleporting you know your
ping is down ⌠but by then youâre dead :]
Oohh⌠So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? Iâll try that, thanks! ;-)>>On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:
Leo M. Cabrera wrote:
Elden Armbrust wrote:
Personally, I would avoid visually representing each players lag in the
game world. This can lead to higher ping players being targeted simply
for that reason.
Base your movements off of time, and only update their movement and
actions when the client receives a packet.
Example:Server sends packets describing players.
Clients receive packet and set state flags (such as velocity, direction,
and actions such as running, walking, etc)
Player A sees Player B running from left to right in front of him.
Player Aâs client, based off of the player data for Player B (moving at
n speed in i, j, k direction representing 3d spatial movement, running
the ârunâ animation), Player Bâs position is estimated.
1 second passes, in which time Player B has stopped moving.
Server sends packets describing players.
Player Aâs client now adjusts, using an âeasingâ animation to go from
the ârunâ animation to the âstandingâ animation.Additionally, take multi threaded server operation into serious
consideration. This is good for many reasons, but the most common of
which is most likely network latency.
A multi threaded server can easy cope with clients which are slow to
respond, or which may become unreachable in the process of a
game/connection.
Also, if this is going to be a âmassively multi playerâ game, consider
using a master/slave setup for your server configuration (and
subsequently, server programming).
This allows what is considered âinstancingâ of various areas of the
playing field, and can often tie in to a dynamic LOD system quite well.
Also, it makes the server load for the primary server much
lower overall, since it has but one job: handling network traffic.One more thing to consider is network bandwidth. While clients are
often capable of downloading data in speeds in excess of 5Mbit, not all
servers or clients are capable of such speeds.
Aim for a lowest common denominator. That will allow more clients at a
lower ping rate overall. A good estimation from my experience is no
more than 20 kilobytes per second.
This does rule out dial up users, but opens the door to almost any and
all broadband users. If you do aim for dial up users, remember that
while 56k modem users are capable of downloading at speeds of upwards of
5.5kilobytes per second, their upload speed can and will be greatly
effected by such. In this case, aim for no more than 3 kilobytes per
second for each upload and download. This can be easily accomplished
with packet scheduling (mind you, Iâm not referring to OS specific
packet scheduling but scheduling built into your application.).Hope that helps you on your way.
-Elden Armbrustskaller wrote:
Hello everyone!
Alright, Iâm making a multiplayer action game, you know, where people
connect to a server and kill each other.
But I want to know how a good client-server should look like⌠Iâve
never done network programming before. Should I do something like, the
client moves, it sends the movement to the server, the server computes
it, and it sends the updated character position to all of the clientsâŚ
Or should I do something else? Thanks!If you really want to do it properly you would use
the equivalent of âphase lockingâ. Thatâs like driving a car.Each client estimates what the other entities are doing,
the server sends the real information (belatedly), and the
client then corrects its estimation.You cannot show the correct position at all times due to lag.
This is not an artifact either â it happens in reality too.
One novelty you might try is give some graphical
hint as to how much lag there is ⌠eg blur vision or
something so the player can take the lag into account.[of course when you see cows teleporting you know your
ping is down ⌠but by then youâre dead :]Oohh⌠So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? Iâll try that, thanks!
Thatâs the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume youâll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.
However, the remaining players will ALSO have to wait the same length of
time to receive data packets from the server, since it cannot do
anything else besides wait for that client which is no longer
reachable. In addition to being able to manage your connections on a
per thread basis, you eliminate the need to manage the connections by
priority. This way, you can simply go about sending and receiving data
on a per thread basis nearly without worry as to what the client is
doing. Depending on the threading package/API youâll be using you may
have the ability to manage errant threads nicely. (i.e. Kill a thread
that is no longer responding due to being hung/blocked/etc)
Oh yes, and one other nice little tidbit of information: When running an
application such as that Iâve described above you should see a marked
and in some cases impressive increase in speed and/or efficiency when
running on a 64 bit processor (especially those with HT or similar
technology).
Perhaps Iâll write up a ânetwork game theoryâ paper and link it in a
post here or something (or even in the message itself).
Good luck
-Elden Armbrust>>> On Sun, 2006-03-26 at 12:59 -0500, Leo M. Cabrera wrote:
[greatly shortend]
Oohh⌠So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? Iâll try that, thanks!Thatâs the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume youâll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.
If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.
Also, having a kernel thread for each player doesnât scale well. MMOâs
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isnât a big deal, but itâll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.
Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which clientâs data will be read on the next
recv() call so a single-threaded server is the simplest solution.On Sun, 26 Mar 2006, Elden Armbrust wrote:
â
Jeff Jackowski
http://ro.com/~jeffj/
However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.Also, having a kernel thread for each player doesnât scale well. MMOâs
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isnât a big deal, but itâll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which clientâs data will be read on the next
recv() call so a single-threaded server is the simplest solution.
Thanks you for the free advertisement for Felix! I couldnât have
stated this better.
Felix threads scale: several million is no problem on an average PC.
Theyâre synchronous, so generally donât require locks: synchronisation
is automatic and handled by channels. Switching is basically just
a single C++ virtual function call, so itâs quite quick.
Felix also does non-blocking async socket I/O behind the scenes
automatically using the fastest available event source for your
platform: IO completion ports for Windows, epoll on Linux,
Kqueue on BSD and OSX, falling back to select() as a last resort.
This is all transparent to the application programmer.
The current library only runs TCP (guess Iâll have to hassle the
async I/O developer to put UDP in âŚ
A binding to SDL and OpenGL is part of the core system. Bindings to any
C or C++ you like are easily created directly in the language,
and rarely require any executable glue logic, since the system
uses the same object model as C/C++ (and in fact generates C++).
Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.
Bugs and problems are fixed almost as fast as with SDL.
[Give me a break! Sam fixes your bug before you report it,
thatâs hard to compete with :]On Sun, 2006-03-26 at 21:08 -0600, Jeff Jackowski wrote:
On Sun, 26 Mar 2006, Elden Armbrust wrote:
â
John Skaller
Felix, successor to C++: http://felix.sf.net
Jeff Jackowski wrote:
[greatly shortend]
Oohh⌠So I use your example, and make a multithreaded server, with one
thread for each player? Is that what you meant? Iâll try that, thanks!Thatâs the model I use (for the most part).
Just in case you were wondering why, I can explain:
Say there are 16 players playing a game, connected to a single threaded
server application.
Player 9 suddenly loses power at his home/apartment/etc. Due to the
nature of TCP/IP (which is the norm, and what I assume youâll be using),
when the server attempts to send a packet to the client, it will try to
get an ACK packet back. However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.
That is true that the blocking sockets are the cause for that, but I
canât agree that UDP gives a better performance.
A faster performance, almost definitely.
An application using UDP cannot know whether data sent to a peer
application is received by the other end or not.
Additionally, for those that reach the destination, there is no
guarantee on the ordering of the data, and the receiver may get
duplicated copies of the same data. This can lead to congestion, or
even âfloodingâ of the client system if the upstream of
the server is significantly large enough. (Which is not uncommon with
game servers)
Also, having a kernel thread for each player doesnât scale well. MMOâs
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isnât a big deal, but itâll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.
Hence the reason i stated that I use that model mostly, and used an
example of 16 players rather than 16,000.
Also, 64 bit CPUs are capable of an exceptionally larger number of
threads than a standard 32 bit CPU, which was why
I mentioned them.
Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which clientâs data will be read on the next
recv() call so a single-threaded server is the simplest solution.
UDP (in my opinion) isnât exceptionally well suited to time critical
applications such as games. Granted, some developers feel differently.
However, in a game where you want to be certain the data is arriving the
way you want it to, TCP is ideal.
Dan Kegle has a great page describing different setups for large
servers. While the site is a bit older now, he keeps it up to date
and the information is still valid for larger server applications. If
the server is to be an MMO style server, itâs definitely worth checking out.
The site is at The C10K problem
-Elden Armbrust> On Sun, 26 Mar 2006, Elden Armbrust wrote:
skaller wrote:> On Sun, 2006-03-26 at 21:08 -0600, Jeff Jackowski wrote:
On Sun, 26 Mar 2006, Elden Armbrust wrote:
However, due to the client no longer being
reachable, the program will wait until a timeout is reached (or in the
worst case scenario, indefinitely) to resume operation.If that ever happens, it is with blocking TCP sockets. Using non-blocking
sockets avoids the problem, and using UDP eliminates the ACK. UDP provides
better performance than TCP, so many commercial games use UDP rather than
TCP.Also, having a kernel thread for each player doesnât scale well. MMOâs
will use a kernel thread for some number of players. Having 10,000+ kernel
threads can keep the kernel pretty busy switching from one thread to
another. For a few players, like 32, it isnât a big deal, but itâll force
the threads to properly synchronize access to data shared between the
threads to avoid race conditions and inconsistant data.Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which clientâs data will be read on the next
recv() call so a single-threaded server is the simplest solution.Thanks you for the free advertisement for Felix! I couldnât have
stated this better.Felix threads scale: several million is no problem on an average PC.
Theyâre synchronous, so generally donât require locks: synchronisation
is automatic and handled by channels. Switching is basically just
a single C++ virtual function call, so itâs quite quick.Felix also does non-blocking async socket I/O behind the scenes
automatically using the fastest available event source for your
platform: IO completion ports for Windows, epoll on Linux,
Kqueue on BSD and OSX, falling back to select() as a last resort.This is all transparent to the application programmer.
The current library only runs TCP (guess Iâll have to hassle the
async I/O developer to put UDP in âŚA binding to SDL and OpenGL is part of the core system. Bindings to any
C or C++ you like are easily created directly in the language,
and rarely require any executable glue logic, since the system
uses the same object model as C/C++ (and in fact generates C++).Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.Bugs and problems are fixed almost as fast as with SDL.
[Give me a break! Sam fixes your bug before you report it,
thatâs hard to compete with :]
pthreads? Arenât those Linux-only? (Iâm using SDL threads)
But anyways, Iâll only allow about 10 to 20 players per server, so I can
allow one thread for each player⌠And⌠I would really like for
dial-up users to be able to play⌠Iâll be sending and receiving the
following struct to and from the users (in the thread):
===================
struct Player
{
// Playerâs rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Personâs name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Playerâs IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};
How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it? Also⌠For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the serverâŚ
Thanks you all!
pthreads? Arenât those Linux-only?
(Iâm using SDL threads)
No. The p stands for POSIX, and there is a Win32 implementation. Still,
unless there is a reason not to, you should stick with SDL threads.
But anyways, Iâll only allow about 10 to 20 players per server, so I can
allow one thread for each player⌠And⌠I would really like for
dial-up users to be able to play⌠Iâll be sending and receiving the
following struct to and from the users (in the thread):===================
struct Player
{
// Playerâs rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Personâs name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Playerâs IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};How much is that? 49 bytes (plus the last 2 variables)?
Probably more when you account for padding. Sort the elements from largest
to smallest in the struct to limit the padding and save memory. Also, by
writting each element to the buffer to send instead of the whole struct,
you can avoid sending a struct with padding over the network. This also
increases the portability of the code because different compilers and
different platforms may align the data differently (itâs 4-byte aligned on
most systems today, but a 64-bit system may use 8-byte alignment). By
writting each element yourself, you can also avoid writting data that
seldom changes except for when it does change, like the playerâs name.
Plus, you can limit the bytes used for a string, like the name, to
strlen(string) + 1 bytes (less if you get fancy about it, but there isnât
a great need).
Will a dial-up
connection handle it?
That depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.
Also⌠For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the serverâŚ
It depends on what your server is doing. If it does little more than
repeat data to all the clients, than the old system you describe can
handle it. Given that struct, I doubt your server will need to do so much
that the old system would have trouble.On Sun, 26 Mar 2006, Leo M. Cabrera wrote:
â
Jeff Jackowski
http://ro.com/~jeffj/
This also
increases the portability of the code because different compilers and
different platforms may align the data differently
Oh crap! Yeah, I forgot about the portability of structs⌠I now
remember from when I learned about binary filesâŚ
That depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.
Does that mean that I have to wait 100ms at the beginning of the
send/receive function thread?
I also have a question now⌠How do I send the data to the clients? I
was thinking of sending an integer saying how much players itâs going to
receive, and then send them⌠Is that alright? Thanks!
PS: Iâm so happy about this game! I hope it comes out wellâŚ
Leo M. Cabrera wrote:
[Message trimmed]
pthreads? Arenât those Linux-only?
(Iâm using SDL threads)
But anyways, Iâll only allow about 10 to 20 players per server, so I can
allow one thread for each player⌠And⌠I would really like for
dial-up users to be able to play⌠Iâll be sending and receiving the
following struct to and from the users (in the thread):===================
struct Player
{
// Playerâs rotation, X-position, and Y-position
int Rotation, xPos, yPos;
// Personâs name
char Name[NAMELENGTH];
// Team: true = red, false = blue
bool Team;
// Playerâs IPv4 address (text representation)
char IPAddress[16];
// IP address
IPAddress IP;
// Socket descriptor
TCPSocket SockDesc;
};How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it? Also⌠For the threads, what processor speed
and/or megabytes of RAM will the server need? I would like it if my old
IBM comp (350MHz P2, 192 MB RAM) was the serverâŚ
Thanks you all!
Well, 49 bytes is quite smallâŚhoweverâŚ
Youâre not sending any animation data (if there is any). Also, I canât
seem to grasp your reasoning for sending the IP adress every update, let
alone more than once.
Once you have the IP in memory, it shouldnât be necessary to send it
over the network any longer unless it changes mid-game. If that
happens, the client will most likely lose connectivity
anyways. Also, the team (as far as I know, Iâm not sure about your
setup) shouldnât need to be sent each update either.
If you were to leave out the IP addresses, the team boolean, and the
TCPSocket type, replacing them with a single char as an identifier,
youâd be left with a structure (not including padding) of
4 + 4 + 4 + NAMELENGTH
So if NAMELENGTH was 32 bytes, that would leave you at 44 bytes per
packet. A 56k modem client could handle ~90 updates per second (plus a
little overhead for padding, etc)
With a proper scheduling setup, you could update 50-100 milliseconds,
which would put you at 440 to 880 bytes per second (not including
overhead) per player.
Itâs highly likely that if you program carefully (i.e. being very
careful to avoid even the smallest memory leak), your 350mhz machine
could potentially handle 32 players 24/7 for quite a while.
If the internet connection is fast enough, that is. For a 32 player game
you would need ~880 * 32 upstream and downstream, which would be
approximately 29kilobytes per second downstream, (~880 * 31) * 32, or
~870 kilobytes per second upstream (31 other players data sent to each
of the 32 players). To reduce the amount of upstream bandwidth youâd
need, you could update less, and reduce the size of the struct.
I would strongly recommend against sending a a character string with the
players name during updates. At a 500ms update cycle and a 12 byte
structure (dropping the name) you can realize an server upstream
requirement of only ~24 kilobytes per second for a 32 player game. This
is why I made such an issue of a good scheduling system for your data
transmission. The slightest miscalculation can lead to poor network
performance. Your current struct (at 49 bytes PLUS the last 2
variables) will most likely create horrible lag if hosted on anything
but a 10 Megabit connection.
Another thing to consider is using a char*3 to represent the rotation of
the character, and converting the resulting data to degrees for use in
your program.
That will shave 1 byte from the structure every update.
I hope that helps but things in a bit of perspective. Please, if my
math is way off on anything, let me know. Just remember that most
everything is an estimation and not a hard number.
Good luck
-Elden Armbrust
This also
increases the portability of the code because different compilers and
different platforms may align the data differentlyOh crap! Yeah, I forgot about the portability of structs⌠I now
remember from when I learned about binary filesâŚThat depends on how often you send updates. Also plan on a 100+ms latency
introduced by the modem.Does that mean that I have to wait 100ms at the beginning of the
send/receive function thread?
No, I just ment that your game should work OK with the greater latency. I
can send data across the US in about 100ms, or across town with a modem in
100 to 150ms.
Since it seems like your trying to keep the networking part pretty simple,
I shouldnât have made an issue out of it. Worry about it after youâve got
the networking code running and the latency is a problem. If it isnât a
problem, donât worry
I also have a question now⌠How do I send the data to the clients? I
was thinking of sending an integer saying how much players itâs going to
receive, and then send them⌠Is that alright? Thanks!
That is certainly the easiest way. Even better is trying to send only data
that has changed. If the gainularity there is all the info on one player
then only when a player does something will the data be sent. Thatâll help
support modem users.
To support that scheme, you may need to tell clients about new players
entering the game and existing ones leaving the game. Then it can be
useful to send messages. Based on the message type, the client or server
will process the data differently. Then you can have connect, disconnect,
and player update messages. Itâs pretty common to use some sort of message
system rather than sending data for all players to all clients every time
through some update loop.
PS: Iâm so happy about this game! I hope it comes out wellâŚ
Good luck, and have fun with it!On Mon, 27 Mar 2006, Leo M. Cabrera wrote:
â
Jeff Jackowski
http://ro.com/~jeffj/
pthreads? Arenât those Linux-only?
(Iâm using SDL threads)
P for âpre-emptiveâ
How much is that? 49 bytes (plus the last 2 variables)? Will a dial-up
connection handle it?
I played D2 for years on a 32K dial up connection with 500 ms
latency (due to server being half way around the world).
PvM was quite playable â not crash hot for PvP though.
The thing is a 56K dialup running 56K upload is the same
speed as 256K download ADSL. So I guess dialup will be
fine for the clients at least.On Sun, 2006-03-26 at 23:33 -0500, Leo M. Cabrera wrote:
â
John Skaller
Felix, successor to C++: http://felix.sf.net
[âŚ]
Using select() with non-blocking TCP, or a higher performace platform
specific method, allows one thread to handle a number of clients. With
UDP, there is no way to tell which clientâs data will be read on the next
recv() call so a single-threaded server is the simplest solution.Thanks you for the free advertisement for Felix! I couldnât have
stated this better.
[âŚ]
The current library only runs TCP (guess Iâll have to hassle the
async I/O developer to put UDP in âŚ
I wrote some posix style stuff to do that (no win32 yet), but havenât
yet tried it out with the demuxers. Itâs one of the many felix add-ons
that Iâve got on the boil, including posix async io (aio_), epoll demuxer
and even an sdl_net demuxer* - a proposito of this, sdl_netâs
SDLNet_CheckSockets only checks for read-readiness and not write.
Whatâs with that?
- lazy manâs way of getting a classic mac/OpenTransport socket impl.
Pre-emptive threading is also supported if you really need it.
However most people use pthreads for control inversion and
to convert blocking I/O to non-blocking I/O neither of which
actually require concurrency, and both of which are supported
directly in the core system.
Itâs felixâs reason for existing. However, if youâre not feeling
adventurous enough to code in a great new language and youâre stuck in
windows (>=nt4) and donât want to worry about concurrency,
you can use fibers (co-operative threads). Nice to see that someoneâs
finally wrapped up the old longjmp/setjmp/jmpbuf-fiddle dance.> From: skaller
Yeah, alright, so all Iâll send is 33 bytes, the rotation, x/y axes,
name, and team flag. (Iâll have to send some more data later on, such as
being on a vehicle or not, weapon, etc⌠:-P)
But, how do I make it only send data when it has changed? Do I make the
client send a boolean flag before anything else, and if itâs false, then
quit receiving data from that user and go to the next one? Thanks you
all!
But, how do I make it only send data when it has changed?
Save previous state, compare, send delta if any.________________________________________________________________________
Gabriel Gambetta
Mystery Studio - http://www.mysterystudio.com
Gabriel on Graphics - http://gabrielongraphics.blogspot.com
Umm⌠err⌠umm⌠Argh, I messed up.
After fixing some compiler errors, I ran the server, and then the
client. I put a test cout line on the find connections loop, and it
detects the client, but after about 1 second of the client connecting,
the clientâs screen loads and the server gets a segmentation faultâŚ
(Note: Both progs are running on the same PC. Maybe thatâs the problem?)
If I disable the data trading on both server and client, the clientâs
screen loads immediately and the server doesnât crash. Iâve got no idea
why this is⌠:-\
Iâve uploaded the files to my host:
http://www.sulfurmidis.com/help/
The send/receive functions in the client are:
SockHnd::RecvPlayerData() (Network.cpp)
SockHnd::SendMyData() (Network.cpp)
For the server, they are:
SockHnd::RecvFromPlayers() (SocketHandling.cpp)
SockHnd::SendToPlayer(int p) (SocketHandling.cpp)
SockHnd::FindConnections() finds connections in the server.
Can you figure what the problem is? All my data is sent in the same
order in both progs⌠Thanks!
Note: Iâll add multiple threads for each user as soon as this gets
fixed.
Umm⌠err⌠umm⌠Argh, I messed up.
After fixing some compiler errors, I ran the server, and then the
client. I put a test cout line on the find connections loop, and it
detects the client, but after about 1 second of the client connecting,
the clientâs screen loads and the server gets a segmentation faultâŚ
Sounds like itâs time to use a debugger. By running the server in a
debugger, youâll see where it crashes by looking at the call stack. If
youâre using gcc, be sure to give it -g to add debugging info. Use watches
to see the value stored in variables and breakpoints to see how the
programâs flow of execution progresses. Insight, Eclipse (with the C/C++
development plugin), and Visual Studio all have good debuggers.On Tue, 28 Mar 2006, Leo M. Cabrera wrote:
(Note: Both progs are running on the same PC. Maybe thatâs the problem?)
If I disable the data trading on both server and client, the clientâs
screen loads immediately and the server doesnât crash. Iâve got no idea
why this is⌠:-\Iâve uploaded the files to my host:
http://www.sulfurmidis.com/help/The send/receive functions in the client are:
SockHnd::RecvPlayerData() (Network.cpp)
SockHnd::SendMyData() (Network.cpp)For the server, they are:
SockHnd::RecvFromPlayers() (SocketHandling.cpp)
SockHnd::SendToPlayer(int p) (SocketHandling.cpp)SockHnd::FindConnections() finds connections in the server.
Can you figure what the problem is? All my data is sent in the same
order in both progs⌠Thanks!
â
Jeff Jackowski
http://ro.com/~jeffj/
Hmm⌠Weird, the error seems to be on the size() method of
std::vector⌠But how can it cause errors? :-/===============
⌠Find
if (this->players.size() >= MAXPLAYERS)
⌠Find again
for (int p = 0; p < this->players.size(); p++)
⌠Find again
for (int p = 0; p < this->players.size(); p++)
⌠No more
What the heck is wrong? Iâm sure this is one of those errors you
canât figure out but then when you do, you say âHeck! Iâm so stupid!â.
Can anyone see whatâs wrong? Thanks!