views:

548

answers:

4

Hello, To start off, I don't know very much about network programming...

So given that, I have a program (process) which needs to listen on 3 ports... Two are TCP and the other UDP.

The two TCP ports are going to be receiving large amounts of data every so often (could be as little as every 5 minutes or as often as every 20 seconds). The third (UDP) port is receiving constant data. Now, does it make sense to have these listening on different threads?

For instance, when I receive a large amount of data from one of the TCP ports, I don't want my UDP stream interrupted... are these common concerns for network programming?

Thanks guys... feel free to ask clarification questions if I'm not being clear.

I'll be using the Boost library on Windows if that has any bearing.

EDIT: After reading this again, I realized I'm not asking a specific question lol... I guess I'm just looking for some thoughts/ideas/guidance on this issue and how to manage multiple connections. Thanks

A: 

Using threads, one per receiving connection, will help keep the throughput high and prevent one port's data from blocking the processing of another ports.

This is a good idea, especially since you're talking about only having 3 connections. Spawning three threads to handle the communication will make your application much easier to maintain and keep performant.

Reed Copsey
+1  A: 

First,

...are these common concerns for network programming?

Yes, threading issues are very common concerns in network programming.

Second, your design idea of using three threads for listening on three different ports would work, allowing you to listen on all three ports simultaneously. As pointed out in the comments, this isn't the only way to do it.

Last, one design that's common in network programming is to have one thread listen for a connection, then spawn a new helper thread to handle processing the connection. The original listener thread just passes the socket connection off to the helper, then goes right back to listening for new connections.

Bill the Lizard
You don't need multiple threads to listen on different ports. Use select() or equivalent to wait for input events on all the listening sockets.
karunski
is select() something from Boost? If not, could you point me towards the documentation for this function so I could find a boost equiv? Thanks karunski
Polaris878
select is from your operating system. In boost, see the asio library which uses select (if appropriate) in its implementation.
janm
@karunski: Thanks. I edited my answer to get rid of that.
Bill the Lizard
Select is part of the original BSD socket API and is implemented in Windows and Unix-like operating systems. Check the MSDN or man pages. Boost::asio is a cross-platform abstraction around select() and other equivalent asynchronous IO APIs.
karunski
+2  A: 

In general, avoid threads unless necessary. On a modern machine you will get better performance by using a single thread and using I/O readiness/completion features. On Windows this is IO Completion Ports, on Mac OS X and FreeBSD: kqueue(2), on Solaris: Event ports, on Linux epoll, on VMS QIO. Etc.

In boost, this is abstracted by boost::asio.

The place where threads would be useful is where you must do significant processing or perform a blocking operating system call that would add unacceptable latency to the rest of the networking processing.

janm
This is wrong. You will have terrible performance if you try to get a single thread to handle multiple sockets.
Spencer Ruport
Rubbish! As you scale up the number of sockets performance will drop significantly if you have a thread per socket. There are many examples of this architecture, including most modern web servers. For older, well known examination, see: http://www.kegel.com/c10k.htmlHave you actually tried to scale these things up?
janm
+1  A: 

Multiple threads do not scale. Operating system threads are far too heavy weight at the scale of thousands or tens of thousands of connections. Granted, you only have 3, so it's no big deal. In fact, I might even recommend it in your case in the name of simplicity if you are certain your application will not need to scale.

But at scale, you'd want to use select()/poll()/epoll()/libevent/etc. On modern Linux systems, epoll() is by far the most robust and is blazingly fast. One thread polls for socket readiness on all sockets simultaneously, and then sockets that signal as ready are either handled immediately by the single thread, or more often than not handed off to a thread pool. The thread pool has a limited number of threads (usually some ratio of the number of compute cores available on the local machine), wherein a free thread is grabbed whenever a socket is ready.

Again, you can use a thread per connection, but if you're interested in learning the proper way to build scalable network systems, don't. Building a select()/poll() style server is a fantastic learning experience.

For reference, see the C10K problem:

http://www.kegel.com/c10k.html

It might scale to 4 or 5 connections... maybe 6 at most. This application is fairly specific in use. Thanks for the tips!
Polaris878