Advertisement

Basic TCP/IP Question

Started by February 12, 2016 11:07 PM
4 comments, last by hplus0603 8 years, 9 months ago

I'm new to network programming and have to write a tool that runs on Windows and communicates with a Linux box over the network. The linux box has a TCP/IP server setup using c++ with boost.

My tool in Windows needs to connect. For the Windows side, I am writing the tool in C# and looked at this tutorial: http://www.codeproject.com/Articles/10649/An-Introduction-to-Socket-Programming-in-NET-using

Basically, the linux box is going to send packets with "event data" to the Windows client at certain times. What's the best way for the client to wait for incoming data? The tutorial above uses a while loop to send/receive data over the network stream. But is just looping and continuously polling for a packet the right design?

-----Quat

This depends on further requirements. While I would say it is bad form to use a busy loop, if it is appropriate or not is really dependent on further requirement information. For instance, if your tool needs to do any significant work when it receives an event, you likely want to use an asynchronous solution with a queue of work to be done. It is really dependent on further information about your requirements though..

Advertisement
If you can block, that's the easiest.
If you can't block, then you have several options:

- If your client has some kind of loop, you can poll the TCP stream each loop, reading as much data as available and processing any complete messages. There will always be the possibility of incomplete messages, so make sure you can store a partially received message across iterations of such a loop.
- If you do not have a loop and you can use C# 5.0, then you can potentially use async/await.
- If you do not have a loop, nor async/await, you can use a thread which does the blocking-style reads internally and somehow posts complete messages back to whatever thread(s) need to process them (or processes them itself, if your messages do not need to be processed on the UI thread).
- If you don't like writing your own thread function and don't have async/await, you can use a BeginRead/EndRead pair with callbacks. (You can also use BeginRead/EndRead in polling mode, if you want)
Generally polling a socket by reading and checking for eagain is not the best option perormance wise especially if you have multiple sockets.

For Linux you should use epoll(), freebsd should use kqueue() and on windows look into io completion ports.

If you can block do so as others have said but never fall into the trap of one thread per socket. Look into thread pools which also works well with what I outlined above.

At a bare minimum use select() but again when you have multiple sockets and not many are active this soon deteriorates in performance.

Hope this helps!
Look up the term "evented I/O", which is the typical way to build high-performance networking (or any kind of I/O).

I've personally been pretty disappointed with the standard .NET facilities for this, though. It's all based on async I/O which is somewhat harder to use for (often) little gain. You can build your own evented I/O system over non-blocking sockets and such.

If any part of your stack is in C or C++, consider libraries like libuv, libev, or libevent. For C#... honestly, let me know if you find an equivalent, because I never have, which is one of the reasons I gave up on using C# for anything and rather stick to C++ (even for tools; Qt obviates the need for C# there), unless of course working in Unity or the like.

Sean Middleditch – Game Systems Engineer – Join my team!

A while loop on a BLOCKING socket is perfectly fine. The thread doing the reading on the socket will just suspend in the kernel until data is availbale.

A while loop on a non-blocking socket will consume all of the available CPU, so that's not that great, unless you're doing scary-crazy ultra-low-latency stuff where you'd expect to see a full stream of packets anyway.

Doing a while loop on a non-blocking socket once per iteration through your game main loop is a fine thing to do, though. If you're running simulation and/or rendering in addition to networking, a very simple structure is:

while (true) {
  read_input();
  while ((size = recvfrom(socket, buffer, ...)) > 0) {
    process network data
  }
  simulate();
  render();
}
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement