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 than 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.

10 Responses to “A Beginner’s Guide to TCP-IP”

  1. Tom Burklin says:

    Good article

  2. abdelrahman says:

    I need what you write in article experimentally using labview or c program

  3. Steve says:

    The steps are there, in the numbered lists. Try doing exactly those steps.

  4. Roger says:

    Hello Steve,

    Thanks for the great article! I’ve been battling for a while now with TCP/IP communication in LabVIEW. I therefore decided to follow your tutorial for the ‘server side’ and wire my own VI. The client is coded in Java on 3rd party hardware. The problem I encounter now is that I get an error 1 in the while loop where the ‘Wait on Listener’ VI is located. I’ve searched the internet endlessly for possible causes but don’t find anything helpful. Perhaps you have seen such an error before? Any assistance would be greatly appreciated.

    Sincerely,

  5. Steve says:

    Roger, ERROR 1 is a bad parameter to the function.
    If you get error 1 on WAIT ON LISTENER, then you are most likely not providing a valid LISTENER ID.
    Check your error signal after you CREATE LISTENER.
    If you get an error there, then you’re not using CREATE correctly.

    If you only have one Network Card, then call CREATE LISTENER with the NET ADDRESS unwired, and supply the PORT number you want to listen on. Your client has to be talking to that port number.
    That has to execute without error before the WAIT ON LISTENER can work.

  6. Roger says:

    Your are absolutely right. My problem was that I provided the wrong ‘Listener ID’ to the ‘Wait on Listener’ VI. I’m able to read all the data from the Java application now into the VI. I think it really works well. I would also like to send data from the VI (server) to my Java application (client). The only problem is that as soon as I wire a data string to the ‘TCP write’ VI I get a null response from the client side. I know that I can successfully read strings in from the client and therefore have a problem in the server code. Would it be best to create another loop for writing out data to the client?

    Thanks for the response. Your article helped me immensely.

  7. Roger says:

    Got it working with only one ‘tcp read’ and one ‘tcp write’ in a while loop. Not to difficult, just a bit intimidating at first working with LabVIEW if you’re not use to dataflow programming. I found the debugging tool in LabVIEW excellent which helped me a lot during the development process.

  8. zeinab says:

    Dear Steve
    hi,i wrote a project by 4 commands in 2 parallel while loop.i set 4 tcp write in the first loop andloop 4 tcp read(4bytes,8bytes,2bytes,2bytes)in the second,but when it running only 2 commands are executed and other are not executed or are executed incorrectly.please help me,it’s very important for me and i don’t have enough time.with regards.

  9. Steve says:

    Impossible to tell without seeing your code. I suggest you go to the NI LabVIEW Support Forum, and ask your question there, showing the code that you mean.

    I can tell you that unless you specifically ORDER the TCP Writes, and ORDER the TCP Reads, then LabVIEW is free to execute them in any order it can, meaning they won’t go out in the order 4,8,2,2, or be read in that order.

  10. zeinab says:

    hi,I wrote that program code in another way: instead setting four commands in 2 parrallel whiles,I set every two commands in 1 parrallel while separately and I set 1 TCP open And 1 TCP close separately,meaning TCP is closed and is opened twice in this program.when running the program,all of the commands are executed but after minutes one of the parrallel while goes out and just one of them is executed and actually only 1 TCP open is executed.I’m losing my job and I have to solve this problem.is there any way for me to send this code for u,because in my opinion just you are professional in this field.I send this question for NI labview support forum but they didn’t answer

Leave a Reply



Testimonial  Contact Info

207-593-8109

Culverson Software

184 Lakeview Drive

Rockland, ME 04841

General questions:

Sales@Culverson.com

Accounts/billing questions:

Accounts@Culverson.com


Logo