Off Topic - Network Programming

I’m writing a contract bridge program and slowly the various modules
bidding, playing, ai are starting to come together. I want to make this
a client/server application with a structure somewhat like the
following:

-clients access the server at a fixed port
-a client can open a new table or join an existing one.
-when all clients at a table signal to start any empty seats are
filled by ai players.
-clients should be able to choose partners at the table

-the server should handle as many tables as system resources
permit.

I played around this weekend with some socket programming and didn’t
seem to have too much trouble with it and have done a little
with pthreads in the past. I plan on using SDL to animate and dress
up the clients.

I have never written a client/server application before and would
appreciate some advice from those with more knowledge than I on
how best to structure the server. ie. fork/thread a process for each
table or client? What’s the easiest way to service multiple clients at
different tables through a single port etc. Is there an online source of
info somewhere? Apologies for the off topic post but this seemed like
a reasonable place to ask.

Thanks in advance

Roy Pluschke <@Roy_Pluschke>

Roy Pluschke wrote:

[snip]

I have never written a client/server application before and would
appreciate some advice from those with more knowledge than I on
how best to structure the server. ie. fork/thread a process for each
table or client? What’s the easiest way to service multiple clients at
different tables through a single port etc. Is there an online source of
info somewhere? Apologies for the off topic post but this seemed like
a reasonable place to ask.

I don’t think you even really need to use multiple processes/threads on
the server.
The magical select() function should do what you need.
Here is how I would structure the server (ugly, inaccuate psuedocode
follows):

struct Client
{
	SOCKET sock;
	...other client data goes here...
};

ClientList clients;	// a collection of connected clients

MainLoop()
{
	bool done=false;

	socket listener = socket();
	... bind to specific port etc...
	listen(listener);

	while( !done )
	{
		fd_set readset;

		...add the listener socket to readset...
		...go through the ClientList and add all the client sockets to

readset…

		select( listener, readset )	// (can't remember other params!)
		if( activity on listener socket )
		{
			accept() connection, create new client
			struct (with new socket) to ClientList
		}
		if( activity on a client socket )
		{
			handle the incoming data
			check for dropped/broken connection
		}
		if( select timedout )
		{
			...do other game stuff...
			(you can specify a timeout for select(). It should
			be high enough precision to use as a main game timer
			eg 10 millisecs might be good for animations. Oh,
			hang on, this is the server so there's no animation...)
		}
	}
}

Game developer mag had a good article ages (ie years) ago that dealt
with this kind of stuff - it was disecting a simple MUD - tinyMUSH I
think… Had a nice, clean, easy-to-understand main loop.

Also note there are some differences between standard unix bsd sockets
and winsock… if you stick to standard calls like socket(), send(),
recv(), listen(), bind(), accept() etc etc the differences aren’t too
serious.
Winsock sockets don’t let you treat the socket as a file descriptor
(like you can under unix), ie no read()/write().

Hope this helps/is of interest…–
Ben Campbell (Antipodean Straggler)
Programmer, Creature Labs
ben.campbell at creaturelabs.com
www.creatures.co.uk

I don’t think you even really need to use multiple processes/threads on
the server.

Right. Unless you have an SMP machine, a correctly written single-threaded
server should give you the best performance, and probably be easiest to
write and debug.

The possible exception is if your server waits for disk I/O a lot and you want
to use the spare cycles in some way. Then multiple threads of control (or
asynch IO, if your platform has it) are needed.

Roy Pluschke wrote:

I have never written a client/server application before and would
appreciate some advice from those with more knowledge than I on
how best to structure the server. ie. fork/thread a process for each
table or client? What’s the easiest way to service multiple clients at
different tables through a single port etc. Is there an online source of
info somewhere? Apologies for the off topic post but this seemed like
a reasonable place to ask.

Thanks in advance

Roy Pluschke

This is uncool to run separate thread or process for each client
connected. BUT! But if there is small number of clients you may succeed
using separate thread per client. If there is too many clients , you
must use select() or poll() call. The main idea is to run separate
thread for managin connections from clients using accept() and in
another thread run so-called event handler that will catch any events on
connected sockets via select() call.------------------------------------------
Burdjanadze Vyacheslav, Software Engineer.
TrustWorks Systems B. V.

razorjack wrote:

This is uncool to run separate thread or process for each client
connected. BUT! But if there is small number of clients you may succeed
using separate thread per client. If there is too many clients , you
must use select() or poll() call. The main idea is to run separate
thread for managin connections from clients using accept() and in
another thread run so-called event handler that will catch any events on
connected sockets via select() call.

If you set the non-blocking option on the socket, accept() will not
block and can be used in the select()/poll() call. I hate threads.–
Pierre Phaneuf
Systems Exorcist

Pierre Phaneuf wrote:

If you set the non-blocking option on the socket, accept() will not
block and can be used in the select()/poll() call. I hate threads.


Pierre Phaneuf
Systems Exorcist

Yes , you right. And you can control timeouts on nonblocked accept of
cource. But threads on SMP machines give you more perfomance.–
With best regards Razor.X.Jackie
"The choise is yours… walk now and live or stay and die"

razorjack wrote:

If you set the non-blocking option on the socket, accept() will not
block and can be used in the select()/poll() call. I hate threads.

Yes , you right. And you can control timeouts on nonblocked accept of
cource. But threads on SMP machines give you more perfomance.

A few points:

  • not many people have SMP machines, and more running threads/processes
    than there are CPU causes a noticeable overhead

  • if you do have two CPU, leave the other free for the X server to do
    its drawing

  • proper multithreaded programming is VERY hard to get right: heck,
    even John Carmack had a f**king hard time getting any improvement out of
    this, do you think you can do better?

  • multiple threads on a single CPU only simulates things happening at
    the same time, with all the complications of having things mess up
    each others like they actually did happen at the same time,
    introducing additionnal scheduling and cache misses overhead: you want
    that for a game?

  • even if this is thought of for SMP machines, most people usually have
    more running threads than there are CPUs, which is bad

  • even with proper programming and an SMP machine, a weak architecture
    (like most x86 SMP machines) will have cache coherency logic putting a
    strangle on performance if you are not extremely careful in not reading
    or writing memory pages that are used by another thread on another CPU

Good luck! :-)–
Pierre Phaneuf
Systems Exorcist

Hi,

I would like to thank those that replied to my post. I have written
a “toy” client and server which seems to do what I want. I have
elected to use poll() rather than select() – perhaps a little less
portable but a little cleaner interface I think – and no threads or
forks. I was testing the rubustness of my code and found that I needed
to work around the SIGPIPE signal for some unexpected situations but
other than that it went pretty well.

During my investigation of socket programming – I read somewhere –
that Carmack had come across a method of reducing the effectiveness
of DoS attacks. It involved using UDP and out of bound data. Has
anyone heard of this method or know where I could find out more
about it???

Roy Pluschke <@Roy_Pluschke>

Roy Pluschke wrote:

During my investigation of socket programming – I read somewhere –
that Carmack had come across a method of reducing the effectiveness
of DoS attacks. It involved using UDP and out of bound data. Has
anyone heard of this method or know where I could find out more
about it???

Roy Pluschke

I’m not sure , but if carmac did somethin , he did it for quake :). try
check out quake sources
especially net_*.c files related to udp. Another good guide to socket
programming in udp is a “UNIX Network Programming” book with sourcecode
applied to.–
With best regards Razor.X.Jackie
"The choise is yours… walk now and live or stay and die"

Roy Pluschke wrote:

I would like to thank those that replied to my post. I have written
a “toy” client and server which seems to do what I want. I have
elected to use poll() rather than select() – perhaps a little less
portable but a little cleaner interface I think – and no threads or
forks. I was testing the rubustness of my code and found that I needed
to work around the SIGPIPE signal for some unexpected situations but
other than that it went pretty well.

Nice! Note that poll() can be simulated with select() if the need arise.
Have autoconf test for poll() and load your select()-based
implementation if it isn’t there.–
Pierre Phaneuf
Systems Exorcist

— razorjack wrote:

Roy Pluschke wrote:

During my investigation of socket programming – I read somewhere

that Carmack had come across a method of reducing the effectiveness
of DoS attacks. It involved using UDP and out of bound data. Has
anyone heard of this method or know where I could find out more
about it???

Roy Pluschke

I’m not sure , but if carmac did somethin , he did it for quake :).
try
check out quake sources
especially net_*.c files related to udp. Another good guide to socket
programming in udp is a “UNIX Network Programming” book with
sourcecode
applied to.


With best regards Razor.X.Jackie
“The choise is yours… walk now and live or stay and die”

Denial of Service attacks have two general characteristics (usually
used together):
-A connection is opened, one after another but never closed. (maxes
connections).
-A packet of a specific size is negotiated to be sent, and only
part is sent. (blocks the connection waiting for the rest of the
packet).

One way to minimize this is to a) close inactive connections after a
period of time. b) close connections that only have sent partial data
packets after a period of time.

This method helps but does not solve the DoS attack problem, as both
methods above in order to allow (good) connections and data have a time
period that is comparativly longer than it takes to perform both the
characteristics multiple times.

A Third and lesser used method of also limiting a DoS is to limit the
number of connections from the same ip at one time.

Using all three methods together to handle DoS attacks works well
against a small group of machines attacking your machine, but can be
defeated if done in large scale.=====
Jason Platt.

“In theory: theory and practice are the same.
In practice: they arn’t.”

ICQ# 1546328


Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.