Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Security

Programmer's Bookshelf


JAN91: PROGRAMMER'S BOOKSHELF

In his "C Programming" column a few months back, DDJ columnist Al Stevens predicted that network programming was what C programmers would be doing a lot of over the next few years. And "for the foreseeable future at least," he went on to say, "the workstations will be MS-DOS machines, and the networks will be NetWare."

This is an important point. I have talked with too many good PC programmers who feel that networks are largely irrelevant to their work, and that network programming is some obscure skill, having nothing to do with the mainstream of programming. Not true on two counts. Networks are indeed a vital part of the PC universe, and are becoming more important every day. And by far the most important local area network (LAN) for PCs is Novell NetWare. A recent survey of Fortune 1000 corporations, in fact, found that Novell had 56 percent of the installed base. The next largest company, IBM itself, had only 22 percent. 3Com, Banyan, and TOPS (now Sitka) together held 20 percent. What this means is, that if you're going to learn about only one LAN, NetWare is it. Fortunately, however, there are general principles involved in network programming. Only one of the books reviewed this month (Steven's Unix Network Programming) attempts to draw out these general principles. The other two concentrate instead on the nitty-gritty details of how to use the programmer's interfaces to particular PC networks. But if you read enough of this stuff, and put together some simple networking applications, the principles emerge, nonetheless.

In this month's "Programmer's Bookshelf," I'll take three recent books on network programming and (somewhat arbitrarily) assign them to three different aspects of network programming: file/record sharing/locking, client-server and peer-to-peer programming, and system administration and utilities.

Of course, there are plenty of other excellent books on networking, the finest being Andrew Tanenbaum's Computer Networks, (second edition, Englewood Cliffs, N.J.: Prentice Hall, 1988). What we're interested in here, though, are books that study network programming, not the merits of broad-band coaxial cable versus twisted pair, or the difference between the pure and slotted ALOHA protocols. No, we're looking for in-depth guidance to programming one of these multiprocessor marvels we call networks.

File and Record Sharing and Locking

One reason network programming is not an obscure niche skill is that even non-network applications must in some limited way be "network aware." That is, files should be used with the understanding that other programs might also be using them at the same time because the file may be located, not on the user's hard disk, but on a file server.

Any decent network makes the location of a file (local vs. remote) transparent to its users, so an application can't assume it is the only user of a file. In fact, this is true even in non-networked situations: Programs that want to behave properly in multitasking environments (such as Desqview and MS Windows) should access files in much the same way as when running on a networked PC. This is one of many similarities between networking and multitasking.

Barry Nance's Network Programming in C is the book to read if you want to learn how to write PC applications that correctly access files. Nance devotes an entire chapter to DOS-level network programming: file sharing, record locking, and so on. This is essential material for all PC programmers.

The material that Nance presents on SHARE.EXE, using the INT 21h function 3Dh (Open file) sharing mode, using INT 21h function 5Ch (Lock or Unlock record), and the like, is absent from most books on DOS programming, the authors of which sadly wimp out that networks "are outside the scope of this book." Let me make the point again: Networks are no longer outside the scope of "normal" PC programming. If you've always avoided specifying a sharing mode when you opened a file because you weren't quite sure that this really pertained to you, or if you've wondered what the locking() and sopen() functions do in Microsoft C, then Nance's Network Programming in C is the place to start.

Client-Server Programming

As it turns out, Nance's book is a fairly complete guide to all aspects of network programming on the PC. In addition to covering the built-in DOS services for networking, he also has excellent chapters on using NetBIOS (INT 5Ch) and using the Novell IPX/SPX services.

But why would you use such services in the first place?

Users often view the file server as the sole reason for the network. In addition to communicating with the file server, however, different machines can also communicate among themselves. In particular, one machine can provide services for other machines on the network, in much the same way as the file server provides all other machines with file services. At the extreme, this can become fully distributed processing.

Thus, the client-server model is the next important aspect of network programming, and requires the ability to send and receive messages (or packets) from one machine to another. NetBIOS is a semi-portable set of services which provides this capability; IPX and SPX are the native Novell services (IPX stands for Internetwork Packet Exchange and is equivalent to Xerox's XNS IDP; SPX stands for Sequenced Packet Exchange and is equivalent to Xerox's XNS SPP).

When learning how to use these services for sending and receiving messages over the network, it is useful to start with something simple. For example, in the networking equivalent of "hello world," instead of calling puts( ) or printf( ) to display a message, you send a request to another machine, and ask it to display the message.

In the pseudocode shown in Figure 1, the program that sends the string "hello world" is the client, and the "display engine" is the server. The server can have multiple clients. The server sits in an endless for(;;) loop, listening for other machines. After another machine (a client) calls it, it receives a request, carries out the request (provides its service), sends back a reply, hangs up on the client, and goes back to listening. No error checking is done in this pseudocode.

Unix programmers will recognize the similarity between the echo and ping programs and this networked version of "hello world." Learning how to write such programs is the proper place to start with client-server programming. The source code for such programs can form the skeleton of many other client-server applications.

Richard Stevens's Unix Network Programming does a good job of showing how to write client-server programs. Chapter 6, on Berkeley sockets, presents six different versions of an echo server (and the corresponding client). Stevens notes that "A pair of client-server programs to echo input lines is a good example of a network application. All the steps normally required to implement any client server are illustrated by this example. All you need to do with this echo example, to expand it to your own application, is change what the server does with the input it receives from its clients."

Stevens's book is essential reading for anyone interested in network programming, even if you don't plan on coming within a million miles of Unix. Of the books reviewed here, this is the one book that makes any attempt to explain network programming in general terms. Even if you have no interest in Berkeley sockets, TCP/IP, XNS, streams, rlogin, RPC, or any of the other topics Stevens covers, reading this book will still help you learn Novell or NetBIOS programming because you'll be learning all about the client-server model of programming. In any case, Stevens also has a surprisingly thorough discussion of the PC-based NetBIOS protocol.

Interestingly, Stevens does not really start discussing networks until page 170 of this massive book. The first three chapters are devoted to various forms of interprocess communication and multitasking. This illustrates an important point: Networking is really just a form of multitasking, where the multiple tasks are running on different machines (processors) instead of on the same machine.

Stevens also discusses file-system services -- open( ), read( ), write( ), and close( ) -- in great depth. Why? Because client-server programming can be viewed as an extension of the file system. In particular with what are called "connection-oriented services," the parallels between network I/O and file I/O are striking. Sending a message to another machine is like writing to a file; receiving a message is like reading from a file. Table 1 presents the basic parallels.

Of course, as Stevens notes in the beginning of Chapter 6, "It would be nice if the interface to the network facilities maintained the file descriptor semantics of the Unix file system, but network I/O involves more details and more options than file I/O."

One of the key differences between client-server communications and "normal" file I/O is that, in a properly written client-server application. I/O is often asynchronous: Control returns to the program before an operation has completed; the application can then be informed (via polling or semaphores) when the operation has completed. Few operating systems have asynchronous file I/O, though the (late?) OS/2 operating system has (had?) two calls, DosReadAsync( ) and DosWriteAsync( ), that map beautifully onto no-wait client-server programming.

That no-wait is a crucial component of client-server programming can be seen from looking again at Figure 1. Our "hello" server runs in an endless loop, listening for requests. When it receives a request, it processes it, then goes back to listening for another request. But what if a machine tries to call the server while it's waiting for a connected client to send it a request? What the server needs to do, as shown in the improved networked "hello" in Figure 2, is do everything no-wait. Figure 2 is grossly oversimplified; in fact, the server should probably be structured as a state machine.

Barry Nance's Network Programming in C shows how to use the no-wait options in NetBIOS and Novell IPX/SPX. Stevens's book does a better job of showing why you want such asynchronous I/O in the first place, however.

Next, there are network utilities. Ralph Davis's NetWare Programmer's Guide is structured around a single system-administration application, written using Novell's NetWare C Interface library that controls access to other programs on the network. The topic of writing system-administration software is often neglected, so it is good to have a book-length treatment of this topic.

Each chapter of Davis's book steps through a different component of the NetWare Application Program Interface (API), each chapter adding new functionality to the sample application. Having one fairly large application is a welcome relief from the standard fare in programming books, which is to have lots of little examples.

Davis is writing a second book on NetWare/386; it will include a lengthy discussion of writing NetWare Loadable Modules (NLMs), a mechanism for writing network applications as dynamic-link libraries.

Anyone interested in programming for Novell NetWare will welcome Davis's book because, while Novell may have the best network for PCs, their programmer's documentation is about the worst. Davis's NetWare Programmer's Guide fills an urgent need for readable information on NetWare programming. While the order in which material is presented is sometimes bizarre ("Miscellaneous Services" belongs in an appendix, for heaven's sake, not in Chapter 2!), the discussions themselves are quite good. I found Chapters 6 (Directory Services) and 14 (Peer-to-Peer Communications) particularly useful. And even though the book's emphasis is on building a single system-administration program, Davis does manage to fit everything in: For example, the chapter on peer-to-peer communications transforms the program into an application server, using IPX (no-wait, of course).

Davis also provides massive documentation of bugs in the NetWare C interface library and builds an improved layer on top of the NetWare library. The book would appear to be indispensable to anyone using Novell's C interface library. In fact, however, I wish Davis had, instead, used the basic Novell assembly language interface (such as INT 21h function E3h and INT 2Fh function 7Ah). There are millions of NetWare machines out there, and you should be able to take this book, walk up to any machine running NetWare, type some NetWare code in, and run it. But Davis's book requires the buggy and unnecessary NetWare C library. In any case, you can use Nance's Network Programming in C as a guide to the Novell assembly-language interface.

Figure 1: Pseudocode for (a) non-networking "hello world" (b) networking "hello world"

  (a)
  /* HELLO.C */
  main()
  {
      puts("hello world");
  }

  (b)

  typedef struct {
       int request;
       int len;
       char buf[MAX];
       } REQUEST_PACKET;          /* client requests to server */
  typedef unsigned REPLY_PACKET;  /* server replies to client */

  /* H_CLIENT.C */
  main()
  {
       REQUEST_PACKET requ;
       REPLY_PACKET reply;
       char *msg = "hello word";
       conn = call (machine running_H_SERVER);
       requ.request = DISPLAY;
       requ.len = strlen(msg);
       strcpy(requ.buf, msg);
       send(conn, &requ, sizeof(REQUEST_PACKET));
       receive(conn, &reply, sizeof(REPLY_PACKET));
       puts(reply == OK ? "ok" : "fail");
       hangup(conn);
 }

  /* H_SERVER.C */
  main()
  {
       REQUEST_PACKET requ;
       REPLY_PACKET ok = OK;
       for (;;) /* endless loop */
       {
           conn = listen(anyone);
           receive(conn, &requ, sizeof(REQUEST_PACKET));
           switch (requ.request)
           {
               case DISPLAY:
                   printf("%*s\n", requ.len requ.buf);
                   send(conn, &ok, sizeof(REPLY_PACKET));
                   break;
               // handle other requests
           }
       hangup(conn);
       }
  }

Figure 2: No-wait networking "hello" server

    /* H_SERVER.C */
    hangup_handler()      /* called when hangup completes */
    {
        // free any buffers allocated in listen_handler, etc.
    }
    send_handler()        /* called when send completes */
    {
        // do nothing
    }
  receive_handler (requ)  /* called when receive completes */
      }
      REPLY_PACKET ok = OK;
      switch (requ.request)
      {
          case DISPLAY:
              printf("%*s\n", requ.len, requ.buf);
              send_nowait (conn, &ok, sizeof(REPLY_PACKET),
                   send_handler);
              break;
          // handle other requests
      }
      hangup_nowait(conn, hangup_handler);
    }
    listen_handler(conn)   /* called when listen completes */
    {
          REQUEST_PACKET requ;
          receive_nowait (conn, &requ, sizeof(REQUEST_PACKET),
              receive_handler);
    }
    main()
    {
          for (;;) /* endless loop */
                 listen_nowait(anyone, listen_handler);
    }

Table 1: Parallels between network I/O and file I/O

  Client-server
  model                File system
  ----------------------------------------------

  Call                 Open
  Listen               "passive Open" (Create ?)
  Send                 Write
  Receive              Read
  Hangup               Close


Copyright © 1991, Dr. Dobb's Journal


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.