Book Review: TCP/IP Sockets in C – Practical Guide for Progammers Second Edition (Chapter 2)

Hello everyone,

I have just made my way through chapter 2. It had a few hiccups but was overall well done.

This chapters introduces you to a simple Client and Server communication process. The client program can send text to the server. The server sends the text back.

Client Code

The client code seems to work fine. I am a big fan of showing the absolute minimum the first time and not including anything else that may get in the way. However, they didn’t do the minimal, (though don’t worry, they were very close to the minimal). They also added two files, so to compile the following files are needed:

  • TCPEchoClient4.c
  • Practical.h
  • DieWithMessage.c

Personally, I have a hard time using code that I don’t understand, so this made me deviate from my purpose of learning sockets to see what is in these other files. Of course, the book give brief explanations too. These files were small and easy to understand.

Practical.h just declares a bunch of functions. However the implementation of these functions are if different .c files.

DieWithMessage.c provides the implementation of two of these functions, DieWithUserMessage and DieWithSystemMessage. These functions are little more than wrappers to output error messages to standard error.

To compile the client code on FreeBSD 8, I did this:

  1. Put the following files in the same directory: /home/jared/Devel/Echo/echoclient
    • TCPEchoClient4.c
    • Practical.h
    • DieWithMessage.c
  2. Change to that directory.
    cd /home/jared/Devel/Echo/echoclient

  3. Run gcc as follows:
    gcc TCPEchoClient4.c DieWithMessage.c -o echoclient

The book includes information about a web site where the code from the book can be downloaded. This web site is here:
http://cs.ecs.baylor.edu/~donahoo/practical/CSockets2/textcode.html
When I downloaded the code from there, the compiling of the client code worked first time and the echoclient works.

When I typed the code in myself (which I like to do because I think it helps me learn better to actually have to type all the code), I had some typos that the compiler errored on and I fixed them.

Server Code (IPv4)
My experience with this first example of server code was…well, lets just say it was confidence building.

The server code also had other files. Not only did it have the same extra files the client code had, but it required even more files:

  • TCPEchoServer4.c
  • Practical.h
  • DieWithMessage.c
  • TCPServerUtility.c
  • AddressUtility.c

We already know what Practical.h and DieWithMessage.c do.

TCPServerUtility.c is similar to DieWithMessage.c in that it provides implementation of functions declared in Practical.h, however, it is not the same in that it is not as short of a file with over 100 lines. It is not as complex as it looks because TCPServerUtility.c provides implementation for only three functions: SetupTCPServerSocket, AcceptTCPConnection, and HandleTCPConnection.

AddressUtility.c provides the implementation to functions declared in Practical.h as well. The following two functions are implemented: PrintSocketAddress, SockAddrsEqual.

I put these files in the same directory and tried to compile just like I did with the client code. However, there was a huge problem when I tried to compile. I got a long lists of errors.

[jared@FBSD8 ~/Devel/Echo/echoserver1]$ gcc TCPEchoServer4.c TCPServerUtility.c DieWithMessage.c AddressUtility.c
TCPServerUtility.c: In function ‘SetupTCPServerSocket’:
TCPServerUtility.c:17: error: ‘IPPROTO_TCP’ undeclared (first use in this function)
TCPServerUtility.c:17: error: (Each undeclared identifier is reported only once
TCPServerUtility.c:17: error: for each function it appears in.)
TCPServerUtility.c:25: error: ‘for’ loop initial declaration used outside C99 mode
AddressUtility.c:6: warning: ‘struct sockaddr’ declared inside parameter list
AddressUtility.c:6: warning: its scope is only this definition or declaration, which is probably not what you want
AddressUtility.c: In function ‘PrintSocketAddress’:
AddressUtility.c:16: error: dereferencing pointer to incomplete type
AddressUtility.c:17: error: ‘AF_INET’ undeclared (first use in this function)
AddressUtility.c:17: error: (Each undeclared identifier is reported only once
AddressUtility.c:17: error: for each function it appears in.)
AddressUtility.c:18: error: dereferencing pointer to incomplete type
AddressUtility.c:19: error: dereferencing pointer to incomplete type
AddressUtility.c:21: error: ‘AF_INET6’ undeclared (first use in this function)
AddressUtility.c:22: error: dereferencing pointer to incomplete type
AddressUtility.c:23: error: dereferencing pointer to incomplete type
AddressUtility.c:30: error: dereferencing pointer to incomplete type
AddressUtility.c: At top level:
AddressUtility.c:40: warning: ‘struct sockaddr’ declared inside parameter list
AddressUtility.c: In function ‘SockAddrsEqual’:
AddressUtility.c:43: error: dereferencing pointer to incomplete type
AddressUtility.c:43: error: dereferencing pointer to incomplete type
AddressUtility.c:45: error: dereferencing pointer to incomplete type
AddressUtility.c:45: error: ‘AF_INET’ undeclared (first use in this function)
AddressUtility.c:48: error: dereferencing pointer to incomplete type
AddressUtility.c:48: error: dereferencing pointer to incomplete type
AddressUtility.c:49: error: dereferencing pointer to incomplete type
AddressUtility.c:49: error: dereferencing pointer to incomplete type
AddressUtility.c:50: error: dereferencing pointer to incomplete type
AddressUtility.c:50: error: ‘AF_INET6’ undeclared (first use in this function)
AddressUtility.c:53: error: dereferencing pointer to incomplete type
AddressUtility.c:53: error: dereferencing pointer to incomplete type
AddressUtility.c:54: error: invalid application of ‘sizeof’ to incomplete type ‘struct in6_addr’
AddressUtility.c:54: error: dereferencing pointer to incomplete type
AddressUtility.c:55: error: dereferencing pointer to incomplete type
[jared@FBSD8 ~/Devel/Echo/echoserver1]$

This was not comforting. I really don’t like to debug sample code but here it goes. In the past, I probably would have stared at these errors and maybe I wouldn’t have had the skills to solve them. However, I was undaunted and resolved these. Let me explain how I resolved them.

  1. TCPServerUtility.c:17: error: ‘IPPROTO_TCP’ undeclared (first use in this function)
    This first error is a problem in TCPServerUtility.c with IPPROTO_TCP variable being undeclared. So I had to figure out where IPPROTO_TCP was declared. It is declared in netinet/in.h, which for some reason is not included. Maybe it only needs to be included on FreeBSD or maybe this is a bug in the Author’s code. Later, I will send the author a link to this post and let him comment on it. For now, I will add this line to the top of the TCPServerUtility.c.

    #include <netinet/in.h>
    
  2. TCPServerUtility.c:25: error: ‘for’ loop initial declaration used outside C99 mode
    This second error can easily be resolved by compiling with C99 mode enabled. This can be added to gcc as a paramter -std=c99.

  3. AddressUtility.c:16: error: dereferencing pointer to incomplete type
    This is not super clear to me at first. However, the line isn’t doing much. So why is the type incomplete? Maybe the struct is not declared yet because again, a file that should be included is not. The struct being called is sockaddr_in and it is defined in netinet/in.h but sure enough, netinet/in.h is not included in AddressUtility.c, so lets add it.

    #include <netinet/in.h>
    
  4. AddressUtility.c:17: error: ‘AF_INET’ undeclared (first use in this function)
    This error in AddressUtility.c is similar to the first error in TCPServerUtility.c. There is probably a header file missing. Again, this may be only a FreeBSD issue or it may be a bug in the author’s code. It is hard to know since I don’t see anywhere where the author specified the platform this was tested on. So I researched and found that AF_INET is declared in sys/socket.h however, again it is not included. Se we add this line to the file.

    #include <sys/socket.h>
    

Ok, now try to compile with this command line:

gcc -std=c99 TCPEchoServer4.c DieWithMessage.c TCPServerUtility.c AddressUtility.c -o echoserver4

Everybody cheer…this time it worked.

It tested the client and the server application together and sure enough, communication occurred. Any string I sent from the client, server sent back.

I was able to use the exact same command with the IPv6 version of the server code, only replacing the TCPEchoServer4.c with TCPEchoServer6.c.

gcc -std=c99 TCPEchoServer6.c DieWithMessage.c TCPServerUtility.c AddressUtility.c -o echoserver6

The rest of the chapter
The rest of the chapter is about what you would expect. The author gives a snippet of code and explains it well. Make sure to take time to read it. This is foundational material for understanding the rest of this book, so it may not hurt to read it twice.

Other notes on the C code
You need to be familar with some common C language features such as typedef and struct as they are used heavily.

typedef
Most the types used are just types that have been renamed with typedef. I am not 100% sure why one would declare a function as follows but I know at least one reason that I will mention:

in_port_t port;

To me this is much more confusing than what it is really saying. in_port_t is just an unsigned short. So it would seem that one should declare the function as follows:

unsigned short port;

However, what if your code is very popular and five years or ten years from now the RFC changes the implementation of a port so that an unsigned int is now required. it is really easy to change in_port_t to point be a typedef of an unsigned int and no other work needs to be done. However, if you declared your variable using unsigned short instead of in_port_t, then every where in your code that you did this, you have to find and manually change it or your code will probably fail.

You can even make a typedef of a typedef and in fact that is what in_port_t is. If you have an IDE (I am using Code::Blocks), then you can highlight the type, right click it and choose something similar to Find Declaration of: in_port_t and it will take you to where this value is defined using a typedef. However, in_port_t is a typedef of uinst16_t, which is a typedef itself of __uinst16_t, which is a typedef of unsigned short. So it is multiple typedefs deep. While sometimes confusing, this can be useful as mentioned above.

struct
C does not have objects or classes. Instead it has structs and one might say that they are the predecessor to objects or classes. However, they are not objects or classes and you should understand how they function. If you understand them, this book will be easier to understand. If you don’t, you will probably struggle. If you aren’t clear on structs, then take time to read about them.

Book Review: TCP/IP Sockets in C – Practical Guide for Progammers Second Edition (Chapter 1)

Hello everyone.

I want to learn sockets on FreeBSD so naturally I bought the following book about it.
TCP/IP Sockets in C, Second Edition: Practical Guide for Programmers (The Morgan Kaufmann Practical Guides Series)

Ok, so chapter one says it is an introduction but would be bettered titles as “Basic Computer Networking Concepts” as it really covers in a very, very broad sense the important points of the OSI model (without mentioning the OSI model). If you are excellent at networking, TCP/IP, etc, this chapter will be a quick read. It is so short that even if you are already an expert, just read it. Who knows, you may find that one line that will teach you something. By the way, I spent four years doing tech support for Nortel Networks Routers, Layer 3 switches, Load Balancers, Wireless APs, etc. I lived in the network world and spent a lot of time in Sniffer Pro or Wireshark (then Ethereal). After which I came to LANDesk (my current employer) where I spent a lot of time working with PXE booting over the network, which uses bootp, dhcp, TFTP and furthered my understanding of client/server communication. So you might think that I should have skipped this chapter entirely. No, I read it.

I found section 1.2.2 – Dealing with Two Versions interesting. This section mentions straight up that socket programmers will have to deal with IPv6. The whole chapter doesn’t just talk of IPv4 only, it includes little snippets of both. I believe the big move to IPv6 will not come quite yet. In 1999, a trainer in my MSCE class said that everyone will be using IPv6 within five years (2004) and if you don’t know, it has really been adopted yet in 2010. It is moving slowing and I think it will continue. Windows 7 and Windows 2008 will cause a lot of adoption, but people are still using Windows 98 in many places even today in 2010. Windows 2000 and Windows XP will take quite a long time to fade away. I predict that some companies (though not many) will still be running Windows XP in 2020. I think that a bigger adoption of IPv6 will occur once the next windows OS (the version after Windows 7) is on the majority of computers. So windows 7 will do what Windows Vista couldn’t and replace XP in the corporate world. The corporate world still must move all their domain environments to Server 2008 (or they may stay on Windows Server 2003 until the next server release after Windows Server 2008 ). The home world will take about five years (2015) to have everyone a majority moved to Windows 7. Anybody on Vista will upgrade to get off that poor unstable operating system and anybody running XP will probably have old hardware that will start dying off and will have to purchase new computers that already come with Windows 7. Moving the operating system is not enough. That aone won’t make everyone move to IPv6. Wireless routers are just starting to support IPv6 such as the DIR-655 Xtreme N Gigabit Router. However, there is a big difference between supporting IPv6 and making IPv6 the default. Most Internet Service Providers (ISPs) still give IPv4 addresses. The infrastructure using IPv4 is so huge it could take a few more decades to completely remove it. You can probably guess that the adoption is going to reach a craze when your ISP starts sending you notices that they are moving to IPv6 and you have to comply and you don’t have a choice, kind of like what just happened with the analog TV service this year. Funny, thing, for a lot of people, me included, their Cable TV service is also their ISP.

Ok, enough rambling about IPv6. It is enough to know that you are going to start to have to deal with it now and at some future time IPv4 will be replaced and you will only have to deal with IPv6.

As for the other topics in the chapter, it is actually amazing that they were able to mention as many topics as they did in such short pages. They mention NAT and DNS and URLs and other important topic (each of which have dozens of large books covering just the one topic). The networking world is a whole other field that have engineers who spend their entire lives becoming experts at just using the equipment, let alone developing software for it. Usually a software developer won’t need to reach such an expert level understanding of networking (unless they are developing the OS for a router/switch or a software such as a firewall).

This chapter was necessary and they added it and I would say they did a good job keeping it short and simple. They did a good job of providing the detail needed at just enough level that a freshman/sophmore in college who knows little about networking and programming would be able to understand the concept of networking enough to have a general idea why they need to code with sockets they way the book will describe.

Stay tuned for a review on Chapter 2.

Update: My review on Chapter 2 is here:
Book Review: TCP/IP Sockets in C – Practical Guide for Progammers Second Edition (Chapter 2)