UNIX Socket FAQ

A forum for questions and answers about network programming on Linux and all other Unix-like systems

You are not logged in.

#1 2003-04-10 10:09 PM

NightCrawler
Member
From: Baton Rouge, LA
Registered: 2003-04-10
Posts: 4
Website

Re: Best portable gaming socket architecture?

I am designing a network based multiplayer game for the sole purpose of learning how to work with network sockets.  Assume that the server/client will communicate via strings, and that the server will need to be able to accomodate multiple concurrent connections (As many as possible).  I would like to develop it so that the code is 100% operational on both Windows (98/2000/XP.etc..) and the FreeBSD unix platform.  I would like to use a TCP stream socket

Now on to the question =)

I'm wondering which network architecture would best suit my purpose?

I'm familiar with Blocking and Non-blocking theory, and a little bit of threading, but I'm not sure what would be the best method to achieve my goal.

Thank you for your advice,

Mark

Offline

#2 2003-04-10 10:35 PM

x33
Member
From: Moscow, Russia
Registered: 2003-04-07
Posts: 20

Re: Best portable gaming socket architecture?


"I'll be Bach" (c) Johann Sebastian Schwarzenegger

Offline

#3 2003-04-10 11:45 PM

NightCrawler
Member
From: Baton Rouge, LA
Registered: 2003-04-10
Posts: 4
Website

Re: Best portable gaming socket architecture?

Thanks man

Offline

#4 2011-06-03 05:08 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Offline

#5 2011-06-03 07:09 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Offline

#6 2012-06-22 10:36 AM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Hi guys

I am working my way through a book based on multiplayer game programming using UDP. Unfortunately i have come across a few typos and sentences that do not make sense so I am starting to judge its reliability, including the code examples.

The code is written in c++ and contains a simple messaging class which contain members that write various data types into a universal buffer. For example

void dreamMessage::WriteShort(short c)
{
char *buf;
buf = GetNewPoint(2);
memcpy(buf, &c, 2);
}

and

void dreamMessage::WriteLong(long c)
{
char *buf;
buf = GetNewPoint(4);
memcpy(buf, &c, 4);
}

Where GetNewPoint() is a function that is used to move around in the buffer. I have noticed that no fix data types are used and int's are not converted into network byte order, does this matter ?

Offline

#7 2012-06-22 12:23 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Well, it matters if you're trying to write portable code that runs on more than a single machine running a single version of a single OS...

For practical purposes, most of the world is little-endian these days, so byte order is less likely to matter as much...  But, it's certainly something that should at least be pointed out in the book: that by sending the raw ints around as-is, you're confining yourself to only communicating with machines of the same byte ordering...  That may be something you're willing to do, and it's generally perfectly practical these days...  But, it still should definitely be pointed out that that's what you're doing, and it's not exactly elegant or "proper"...

On the other hand, making assumptions about the size of native "long" is just crazy...  That WriteLong() function is totally broken on 64-bit systems, where "long" will generally be 8 bytes in size...  And, 64-bit systems aren't exactly uncommon these days!  What they should ideally have are functions like write16(), write32(), write64(), which take int16_t, int32_t, int64_t arguments...  Internally, in your own code, working with the native int types is perfectly fine, but when you are communicating over the network with another machine, which could be of a totally different architecture, you should always stick to fixed-size types which are always the same everywhere...  In general, assuming "short" will always be 16-bit and "int" will always be 32-bit is probably safe enough...  (These days, anyway...  Back when 16-bit systems were still commonplace, you couldn't safely assume the size of "int", either...)  But, you're definitely not safe assuming anything about the size of "long"...  If you absolutely have to make such assumptions, then at the very least throw in some verifying assert()'s or something, which kill you dead if your assumptions are broken on the particular system you're running on...

Offline

#8 2012-06-22 05:54 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Offline

#9 2012-06-22 08:08 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Offline

#10 2012-06-23 01:09 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Thanks Rob,

I done a quick search on a message queue system for IPC on unix and discovered msgsnd() and  msgrcv(), these look really cool to implement, have you ever used this family of functions ?

Offline

#11 2012-06-23 03:47 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Ah, more of the old SysV IPC crap...  I don't think I've touched any of that stuff since college...  You'd probably be better off going with the Posix alternative implementation for any of those old creaky SysV IPC things...  In this case, Posix message queues: mq_open(), mq_send(), mq_receive(), etc...

However, I'd only bother with stuff like explicit message queues if you need to communicate between processes...  If you're just talking about communicating between threads, you don't need any of that crap...  They share the same memory space already!  So, you just need one thread to stick a message on a list/array/queue/whatever and simply signal the other thread that it's there for it to get...

Offline

#12 2012-06-25 09:59 AM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Ok thanks for that Rob.

Now just out of interest how would one implement a 'queue' ? I can work it with lists or arrays no problem but I've been searching high low about queues and all I get in return are those functions listed above, nothing on how to implement them from scratch :-(

Edit: I just wanted to add that all the source code I have seen that use select() loop from 0 to the maximum socket descriptor, wouldn't the performance increase if you looped from the minimum descriptor (normally the listener) to the maximum ?

For example, from what I've seen on windows (unix maybe different) but the first descriptor always has a value higher than '100', e.g the listener being '116' then additional accept()ed sockets ranging from 128, 138, 142 etc
This obviously means that if you loop from 0 then you perform 115 iterations before the first socket gets checked.

Last edited by RipRage (2012-06-25 12:10 PM)

Offline

#13 2012-06-25 12:17 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

A queue is merely a FIFO list...  If you can make a linked list, you can make a queue: simply always add new data at one end and remove data from the other end...  That's all that's required, really...  There's no requirement to use a linked list, but it's the most natural and flexible method which puts no limits on the amount of queued data (aside from free RAM)...  Just keep a pointer to both the head of the list and the tail so you can always easily and efficiently add onto the tail and remove from the head...  (And, of course, protect them with a mutex lock when adding or removing data...)

Offline

#14 2012-06-25 12:24 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Offline

#15 2012-06-25 12:53 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Offline

#16 2012-06-27 10:04 AM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

One last question on this, I'm trying to find the best logic for the send/recv() operations for passing all different kinds of messages and argcs. I.e messages that contain registration, login, game data etc. I can only think of two methods. The first, write to the buffer any data that corresponds to the message type and slap a header on it, this will cause overhead due to two calls to recv() for each message. The second using a universal structure which contains everything needed for all messages, fill in the only parts needed for the message type and send and recv the whole thing with writev and readv(). What I don't want to do is get packets mixed up. Any suggestions ?

Offline

#17 2012-06-27 12:19 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Last edited by RobSeace (2012-06-27 12:23 PM)

Offline

#18 2012-06-27 04:44 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Best portable gaming socket architecture?

Another way is to have a big receive buffer and call one recv().
And then do the message parsing on that buffer. This way you
can receive multiple messages at once too. In the rare case that
you receive a partial message, copy it to the front of the buffer
and call receive for the remaining bit (you may need to store it
outside the main buffer until the rest arrives though).

But it depends on what you do with the messages. If they are short
lived and thrown away immediately after processing, then the above
method works well, as you can use one shared receive buffer for all
clients. But if you have a buffer for each peer, or you need to keep
the data around and will call a malloc() for each message anyway,
then doing two reads() makes a lot more sense.

Offline

#19 2012-07-09 05:48 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Thanks for your replys! Very helpful as always.

As it stands, I have implemented the messaging system, the inbound and outbound queues, and now working on the main communication thread. I just wanted to ask what would be the best way to deal with login/registration request besides normal game messages.

At the moment I am accept()ing and adding all new connections to the master fd_set. calling my ReadPacket() fuction for each readable socket which then dumps any incoming data onto the inbound message queue. I am using specific messages to divide the normal game data from the login/registration request so I can communicate with individual requests and game data which gets sent to all.

Comunication thread logic: check the first writable socket in the set, if the message to send flag is set to false, grab the mutex and check the outbound queue. If an outbound message is ready then copy it and release the mutex. Check the message type, I'f it's for an individual send it to the corresponding socket Otherwise if it's a game message send to all, reset the message to send flag. etc.

What I am trying to do is keep the communication thread running as quick as possible, I.e literally just recv()ing data and adding it to the inbound queue, followed by checking the outbound queue and sending the data.

I feel that I should not be adding new connections I.e login request to the master set straight away, only add them if login is successful but that would require adding additional recv() sends() after accept() or passing the new socket to the worker thread and allow it to recv() send() login request and response and then adding the socket to master fd set. *shrug*

Offline

#20 2012-07-09 07:04 PM

i3839
Oddministrator
From: Amsterdam
Registered: 2003-06-07
Posts: 2,239

Re: Best portable gaming socket architecture?

I would keep game/login logic completely separate from the networking system.
So I would treat all connections equally and just add it to the set immediately.

State tracking like being logged in or not and how to interpret messages should
be handled elsewhere and not directly by the networking code. If you have a need
to group clients for other reasons, you could add a  "not logged in" group.

Offline

#21 2012-07-09 09:07 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Offline

#22 2012-07-13 01:30 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Thank you both for the tips! very helpful indeed

I would like to have your honest opinion on when would be the best time to check the outbound queue?

x33 above mentions beejs source code on select() which leads me to believe that he suggests checking the outbound queue after every received packet ?

I'm not sure if I agree with this, would it be better to first run through all incoming connections, receive and append any available data and then run through the outgoing queue sending all messages and popping them from the queue ?

It's hard to try and get everything synchronised but we will get there eventually ;-)

Offline

#23 2012-07-13 07:09 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

It's probably not wise to just check the outbound queue for stuff ready to send only when you're woken up from the readability select(), because if it should happen the clients all go idle for a while, you could miss out on sending outbound data for quite some time...

What you probably need is a way for the other threads that stick stuff on the outbound queue to signal the main I/O thread that there is new data there ready to go...  And, since you're already sitting in a readability select(), then the natural signaling method would probably be a simple pipe()...  Stick the read end of the pipe into your select() fd_set, then when a thread adds data to the outbound queue it writes a single byte down the write end of the pipe, which will cause the read end to select() readable, and your I/O thread can read the byte out of the pipe and then know to process through the outbound queue for data to send...

Offline

#24 2012-07-13 07:14 PM

RobSeace
Administrator
From: Boston, MA
Registered: 2002-06-12
Posts: 3,839
Website

Re: Best portable gaming socket architecture?

Or, you know, now that I think about it...  Why not simply replace your outbound queue with the pipe!  When threads have new data to send out, just write it down the pipe...  When the pipe selects readable, the I/O thread can just read the data from the pipe and send it off wherever...

Or, does Windoze not have pipe()?  Oh, shit, even if it does, their broken select() only works on sockets, doesn't it?  Ugh...  Do they support AF_UNIX/AF_LOCAL sockets?  You could use a socketpair() of those instead of a pipe()...

Offline

#25 2012-07-13 08:30 PM

RipRage
Member
From: England
Registered: 2010-01-06
Posts: 146

Re: Best portable gaming socket architecture?

Offline

Board footer

Powered by FluxBB