A Beginner's Guide to TCP-IP

Talk amongst yourselves.

I guess this Internet thing is here to stay, huh? It can be daunting at first, what with looking at the complexities of a web page and the realization that banks use it to launch nuclear missiles and the military can conduct a million two-dollar transactions in a day (or something like that…:-). If you grew up with RS-232 and GPIB as the ways for one box to talk to another, it might seem seriously complicated, what with clients and servers and HTTP and proxies and routers and ports and …

It’s not.

It’s not even close.

The truth is, it’s a whole lot simpler than either of those technologies, at least from a software point of view. And a whole lot more versatile, as well. There’s one analogy that brought it home for me:

TCP communications is just like using a telephone.

This is true in a lot of ways:

  • To make a TCP connection, you have to open a connection to a given IP address (dial a phone number).
  • To answer a connection, you have to be listening for one (have your ringer turned on),
  • Once the connection is established, the roles of client and server are established by convention, not by any property of the connection. Either end can send at any time (you can call the office of the U.S. President, but who is the client and who is the server is debatable).
  • A port is the final destination-specifying part of an address (like an extension).
  • Figuring out what you’re going to say and how you’re going to say it takes a whole lot more thought than establishing the connection itself.

How to Use TCP in Your Programs

First, decide how it is to be used. By convention, the “client” is the piece that initiates the call and requests information, and the “server” is the piece that answers the call and dispenses information. Note that this is a general guideline, not a rule: the connection works both ways. How does that relate to your situation? Which piece is going to initiate the call? Which piece will answer? Do you have control of both ends of the connection? If you don’t, you have to play by the rules already established by the other end (if you want to dial up a web server, you can; but what you get back is not under your control).

Next, establish how you’re going to obtain the server’s IP number for the client. If you have a local area network (LAN), you can just fix the address (192.168.xxx.xxx) and store a constant somewhere, or offer it as a user-configurable field. If your project is large-enough scale, you can register a domain name, and the DNS service will connect the name (www.culverson.com) to your IP number. That’s only useful if it’s supposed to be a publicly-available service though. For most small scale projects, make it a user-configurable field and be done with it.

You need to know several VIs, all in the PROTOCOLS: TCP palette:

  • TCP Open Connection
  • TCP Close Connection
  • TCP Write
  • TCP Read
  • TCP Create Listener
  • TCP Wait on Listener

For the client side, it’s extremely easy:

  1. Call TCP OPEN CONNECTION with the IP Number you want to connect to, the PORT number you want to connect to, and a suitable timeout. “Suitable” requires a bit of thought: if you’re dialing across the room on a clean network, 100 mSec might be adequate, but if you’re dialing across the world, then 10000 mSec might be more appropriate.
  2. Call TCP WRITE, as appropriate. For TCP WRITE, you have to provide the CONNECTION ID (obtained from TCP OPEN CONNECTION ), and a string to send. It doesn’t have to be ASCII, you can flatten anything into a string and send it. That is especially useful for sending binary data.
  3. Call TCP READ, as appropriate. For TCP READ, you have to provide the CONNECTION ID (obtained from TCP OPEN CONNECTION ), a MODE (more about that later), and a NUMBER OF BYTES TO READ (more about that later).
  4. When you’re done, call TCP CLOSE CONNECTION.

For the server side, it’s only a tad more complicated:

  1. Call TCP CREATE LISTENER. This gives you a LISTENER ID.
  2. In a WHILE loop, call TCP WAIT ON LISTENER, using the LISTENER ID you just got. Usually you use a timeout of -1 (never). You’ll get out of it later. This suspends the loop until a connection comes in; for that reason you have this in a separate loop from your main code.
  3. When a connection comes in, the WAIT ON LISTENER function returns to you without an error. You want to check the error code – when it returns WITH an error, you want to terminate your loop.
  4. If you have no error, then the CONNECTION ID out of WAIT ON LISTENER is valid. Call TCP READ and TCP WRITE, as appropriate.
  5. When you’re done with this connection, call TCP CLOSE CONNECTION on the CONNECTION ID, and repeat the loop, to wait on another connection to come in.
  6. When you’re ready to quit the program, or at least quit listening, call TCP CLOSE CONNECTION, but use the LISTENER ID as an input for that. That will cause WAIT ON LISTENER to terminate with an error, and your loop to stop.

For the MODE parameter to TCP READ, there are four choices, as detailed in the HELP for that function. I almost always use BUFFERED, so that I get either nothing, or the amount of bytes I requested. When talking to an instrument that sends Carriage Returns / Line Feeds, I will use CRLF mode, so that I get things a line at a time. I have never used the other two modes. I also usually use a timeout value of zero, so that it returns immediately, with either a whole message to deal with, or a timeout error. In any case, I have better things to do that wait around for the message to come in.

So, how many bytes do you request? Good question. There are two methods in common use, each appropriate to some circumstances. The first is to design a protocol that uses a fixed length. If all messages can be sent in 13 bytes, then use 13 as a message length, and you’re done. Anything that is shorter can be padded up to 13 bytes, and it’s OK. For other situations, that is not adequate. In one project I’ve done, some messages can be a single byte, others can be several thousand. It would be very wasteful to pad every message up to 4000 bytes, so a better scheme is needed. The answer is to send a fixed-size header, and then a variable-sized data portion. The header includes a number specifying the length of the data portion. So each receive operation must actually read twice; once to read a header, and once to read the payload. LabVIEW documentation suggests that it is better(faster) to combine the header and payload and do a single TCP WRITE than to do two separate TCP WRITEs for the header and payload. That means the OS handles it as one transmission, not two, which makes sense.

So, for my case, I designed a HEADER typedef (you are using typedefs, aren’t you?), consisting of two fields: a COMMAND field (1 byte) and a PAYLOAD SIZE field, a two byte integer (U16).

The COMMAND field contains an enumerated typedef, defining what type of message this is. The SIZE field specifies the payload to follow.

The receiving end can therefore use a common procedure to receive messages. First you read 3 bytes from the connection, and unflatten it into a header. Then you use the PACKET SIZE field of that header to determine how much more to read for the payload.

That’s all there is to it! Well, except for that pesky bit about what to say. You still need to decide what the protocol is going to be. That’s just another way of defining who’s going to say what when. Does the server answer with a “Hello”, or does the server expect the client to ask the question first? If you control both ends, it’s entirely up to you.

Enjoy.

Leave a Reply


    Affiliations

    • TI Alliance

    Calendar

    May 2012
    M T W T F S S
    « Mar    
     123456
    78910111213
    14151617181920
    21222324252627
    28293031  

Testimonial  Contact Info

207-790-0949

1-877-676-8175 (toll-free)

Fax: 1-815-572-8269

General questions:

Sales@Culverson.com

Accounts/billing questions:

Accounts@Culverson.com


Logo