Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
6.  Socket Interfaces Client-Server Programs Sockets and Servers  Previous   Contents   Next 
   
 

Sockets and Clients

This section describes the steps taken by a client process. As in the server, the first step is to locate the service definition for a remote login.

    bzero(&hints, sizeof (hints));
	    hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
	    hints.ai_socktype = SOCK_STREAM;

	    error = getaddrinfo(hostname, servicename, &hints, &res);
	    if (error != 0) {
		  (void) fprintf(stderr, "getaddrinfo: %s for host %s service %s\n",
		                 gai_strerror(error), hostname, servicename);
		  return (-1);
	    }

getaddrinfo(3SOCKET) returns the head of a list of addresses in res. The desired address is found by creating a socket and trying to connect to each address returned in the list until one works.

for (aip = res; aip != NULL; aip = aip->ai_next) {
		/*
		 * Open socket.  The address type depends on what
		 * getaddrinfo() gave us.
		 */
		sock = socket(aip->ai_family, aip->ai_socktype,
		    aip->ai_protocol);
		if (sock == -1) {
			perror("socket");
			freeaddrinfo(res);
			return (-1);
		}

		/* Connect to the host. */
		if (connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) {
			perror("connect");
			(void) close(sock);
			sock = -1;
			continue;
		}
		break;
	}

The socket has been created and connected to the desired service. The connect(3SOCKET) routine implicitly binds sock, because sock is unbound.

Connectionless Servers

Some services use datagram sockets. The rwho(1) service provides status information on hosts connected to a local area network. Avoid running in.rwhod(1M) because it causes heavy network traffic. The rwho service broadcasts information to all hosts connected to a particular network. It is an example of datagram socket use.

A user on a host running the rwho(1) server can get the current status of another host with ruptime(1). Typical output is illustrated in the following example.


Example 6-7 Output of ruptime(1) Program

itchy up 9:45, 5 users, load 1.15, 1.39, 1.31
scratchy up 2+12:04, 8 users, load 4.67, 5.13, 4.59
click up 10:10, 0 users, load 0.27, 0.15, 0.14
clack up 2+06:28, 9 users, load 1.04, 1.20, 1.65
ezekiel up 25+09:48, 0 users, load 1.49, 1.43, 1.41
dandy 5+00:05, 0 users, load 1.51, 1.54, 1.56
peninsula down 0:24
wood down 17:04
carpediem down 16:09
chances up 2+15:57, 3 users, load 1.52, 1.81, 1.86

Status information is periodically broadcast by the rwho(1) server processes on each host. The server process also receives the status information and updates a database. This database is interpreted for the status of each host. Servers operate autonomously, coupled only by the local network and its broadcast capabilities.

Use of broadcast is fairly inefficient because it generates a lot of net traffic. Unless the service is used widely and frequently, the expense of periodic broadcasts outweighs the simplicity.

The following example shows a simplified version of the rwho(1) server. The sample code receives status information broadcast by other hosts on the network and supplies the status of the host on which it is running. The first task is done in the main loop of the program: Packets received at the rwho(1) port are checked to be sure they were sent by another rwho(1) server process and are stamped with the arrival time. The packets then update a file with the status of the host. When a host has not been heard from for an extended time, the database routines assume the host is down and logs this information. Because a server might be down while a host is up, this application is prone to error.


Example 6-8 rwho(1) Server

main()
{
   ...
   sp = getservbyname("who", "udp");
   net = getnetbyname("localnet");
   sin.sin6_addr = inet_makeaddr(net->n_net, in6addr_any);
   sin.sin6_port = sp->s_port;
   ...
   s = socket(AF_INET6, SOCK_DGRAM, 0);
   ...
   on = 1;
   if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof on)
         == -1) {
      syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
      exit(1);
   }
   bind(s, (struct sockaddr *) &sin, sizeof sin);
   ...
   signal(SIGALRM, onalrm);
   onalrm();
   while(1) {
      struct whod wd;
	      int cc, whod, len = sizeof from;
      cc = recvfrom(s, (char *) &wd, sizeof(struct whod), 0,
         (struct sockaddr *) &from, &len);
      if (cc <= 0) {
      if (cc == -1 && errno != EINTR)
         syslog(LOG_ERR, "rwhod: recv: %m");
      continue;
      }
      if (from.sin6_port != sp->s_port) {
         syslog(LOG_ERR, "rwhod: %d: bad from port",
            ntohs(from.sin6_port));
         continue;
      }
      ...
      if (!verify( wd.wd_hostname)) {
         syslog(LOG_ERR, "rwhod: bad host name from %x",
            ntohl(from.sin6_addr.s6_addr));
         continue;
      }
      (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
      whod = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
      ...
      (void) time(&wd.wd_recvtime);
      (void) write(whod, (char *) &wd, cc);
      (void) close(whod);
   }
   exit(0);
}

The second server task is to supply the status of its host. This requires periodically acquiring system status information, packaging it in a message, and broadcasting it on the local network for other rwho(1) servers to hear. This task is run by a timer and triggered by a signal.

Status information is broadcast on the local network. For networks that do not support broadcast, use multicast.

 
 
 
  Previous   Contents   Next