-->

Previous | Table of Contents | Next

Page 600

This process is called multiplexing and is the loop at the core of many network-aware applications, although the actual mechanics can be concealed by sophisticated dispatchers or notifiers that trigger events based on which connection is ready to be read from or written to. Something else lacking in Listing 28.10 is the minimum amount of error checking and signal handling that cleans up connections when a quit signal is received.

I/O Multiplexing with TCP

In order to demonstrate TCP multiplexing, it is necessary to create different programs for the client and server. The server, tcplisten, is shown in Listing 28.11 and is the one that requires the most scrutiny. The client, tcptalk, is on the book's CD-ROM and won't be reprinted here because it resembles the server so closely. I'll explain how the client works as I cover the server.

Listing 28.11. tcplisten.

 1: #!/usr/bin/perl

 2:

 3: use Socket;

 4: require "./network.pl";

 5:

 6:  $NETFD = makelisten($ARGV[0]);

 7:

 8:  while (1) {

 9:

10:     $paddr = accept(NEWFD, $NETFD);

11:

12:     ($port, $iaddr) = sockaddr_in($paddr);

13:

14:     print "Accepted connection from ", inet_ntoa($iaddr),

15:     " on port number ", $port, "\n";

16:

17:     $rin = "";

18:     vec($rin, fileno(STDIN), 1) = 1;

19:     vec($rin, fileno(NEWFD), 1) = 1;

20:

21:     while (1)

22:

23:      select $ready = $rin, undef, undef, undef;

24:

25:      if (vec($ready, fileno(STDIN), 1) == 1) {

26:         sysread STDIN, $mesg, 256;

27:         syswrite NEWFD, $mesg, length($mesg);

28:      }

29:      if (vec($ready, fileno(NEWFD), 1) == 1) {

30:         $bytes = sysread NEWFD, $netmsg, 256;

31:         if ($bytes == 0) { goto EXIT; }

32:         print "$netmsg";

33:         $netmsg = "";

34:      }

35:     }

36:     EXIT: close NEWFD;

37:     print "Client closed connection\n";

Page 601


38:  }

39:

40:  close $NETFD;

The server creates a listening socket in line 6 and then immediately enters a while loop. At the top of the loop is a call to accept(). By placing this in a loop, the server can repeatedly accept client connections, like our other TCP server. The listen socket, $NETFD, can accept more than one connection, regardless of the state of any file descriptors cloned from it using accept().

accept() returns the address of the connecting client. You use this address in lines 12 and 14 to print out some information about the client. In line 12, you use sockaddr_in() to reverse engineer the fully qualified address back into a network address and a service port. Then you use print to display it on the terminal. S the call to inet_ntoa() embedded in the print command.

Then you set up for a select() loop using almost the same code as Listing 28.10. There is, however, a key difference in the way the network connection is handled. You are reading with sysread() again, but you are saving the return value.

When a peer closes a TCP connection, the other program receives an end-of-file (EOF) indication. This is signified by marking the socket as ready for reading and returning zero bytes when it is read. By saving the number of bytes returned by sysread(), you are able to detect a closed connection and record it and then return to accept() at the top of the outer while loop.

The following is a server session, followed by the client session that is communicating with it. The client is tcptalk, which is included on the CD-ROM, as is a copy of tcplisten.

$ ./tcplisten test

Accepted connection from 10.8.100.20 on port number 29337

Hello, world.

Goodbye, cruel....

Client closed connection





$ ./tcptalk iest test

Hello, world.

Goodbye, cruel....

^C

Advanced Topics

During the course of this chapter, I've alluded to a few advanced topics. Let's take some time out to touch on a few of them individually.

One of the biggest issues for TCP applications is queueing messages. Depending on the nature of the data being transferred, the network bandwidth available, and the rate at which clients can keep pace with the data being delivered, data can queue up. Experienced application designers generally specify a queueing mechanism and the rules associated with it as part of the initial product description.

Page 602

UDP applications have to wrestle with data reliability, and some schemes rely on message sequence numbers. All nodes involved in a transaction (or a series of transactions) keep track of a numbering scheme. When a node receives a message out of order, it sends a negative acknowledgment for the message that it missed. This sort of scheme greatly reduces traffic when everything goes well but can become very expensive when things fall out of sequence.

Some applications can use asynchronous I/O in order to service network traffic and other tasks in a single application. This scheme registers interest in a signal that can be delivered whenever a file descriptor has data ready to be read. This method is not recommended, though, because only one signal can be delivered for all file descriptors (so select() would still be needed) and because signals are not reliable.

Security is always a big issue, regardless of the protocols being used. UDP is being used less and less over the Internet, essentially because it is very easy to impersonate a host when no connections are required. Even TCP connections, however, can be "spoofed" by someone who has an understanding of the Internet Protocol and WAN technology. For that reason, applications that require a high level of security don't rely on TCP to keep them secure and tend to use encryption and authentication technology.

Summary

This chapter covers a lot of ground in a short time. I introduced essential networking concepts, such as the components of a network address and how an application can form one from symbolic host and service names by looking them up with the resolver functions.

Sockets, the most commonly used network programming interface, are used throughout the chapter. This API enables us to treat network connections and data streams like files, which shortens the network programming learning curve and also makes applications easy to design and maintain.

I also discussed the two most commonly used protocols on the Internet, TCP and UDP. TCP, a connection-oriented protocol, has very robust reliability mechanisms that allow an application to use the network without worrying too much about whether the messages it is sending are reaching the other end. This reliability does carry a price, however, because TCP comes with a certain degree of overhead in terms of speed and bandwidth. TCP also supports only two-way communication, so clients and servers that need to communicate with more than one node have to maintain multiple connections, which can be expensive.

UDP, on the other hand, is a connectionless, datagram-oriented protocol. It comes with virtually no overhead, but applications have to provide their own reliability mechanisms. UDP also supports broadcast, which can be convenient, but also represents a potential problem for some networks.

Previous | Table of Contents | Next