/* * A simple socket client, borrowed and commented from * pp. 45-46 of "Computer Networks: A Systems Approach", * 2nd Edition, by * Larry L. Peterson and Bruce S. Davie. * * Usage: * client server-name * * Exit values: * 0: Success * 1: Incorrect number of parameters * 2: Unknown host * 3: Trouble creating a socket * 4: Trouble connecting */ /* Include libraries. */ #include #include #include #include #include /* Define constants. */ #define SERVER_PORT 5432 #define MAX_LINE 256 /* The script that drives our program. */ int main(int argc, char *argv[]) { /* I. Declare Variables */ /* A struct is a group of fields (record). This particular one has information on the current host. */ struct hostent *hp; /* The address of something. */ struct sockaddr_in sin; /* The name of the host, stored as a string. */ char *host; /* An array of MAX_LINE characters. */ char buf[MAX_LINE]; /* The number of the socket we use. */ int s; /* The length of a message that was just read. */ int len; /* II. Check arguments. * This program requires one argument. * Note: argc gives the number of arguments, with the program * name counting as one of them */ if (argc == 2) { host = argv[1]; } else { fprintf(stderr, "Usage: client servername\n"); exit(1); } /* III. Get information on the server. */ /* Translate host name into IP address. */ hp = gethostbyname(host); /* Hack! Many C routines, including gethostbyname, return the * null (0) pointer when they fail. In C, 0 is "false". */ if (hp == NULL) { /* fprintf ("file print formatted") takes N arguments * the file (stream) to print to, a pattern to print, * and things to put in the pattern. The parts of the * pattern are typically %s (for string), %d (for integer), * or %f (for float). */ fprintf(stderr, "unknown host: %s\n", host); exit(2); } /* IV. Set up the address. */ /* (1) Clear the structure. * & gives the address of something * (char *) is a cast (to a pointer) * sizeof() gives the number of bytes used by a structure * bzero(pointer,len) sets len bytes to 0. */ bzero((char *)&sin, sizeof(sin)); /* (2) Set the fields. * This is a lot like Java: object.field = ... */ sin.sin_family = AF_INET; /* Copy bytes. Parameters are pointer to source, pointer * to destination, and number of bytes to copy. */ bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); /* Different machines may represent numeric values differently. * Hence, there are standard methods for converting from "host" * to "network" numbers. htons is "host to network short" */ sin.sin_port = htons(SERVER_PORT); /* V. Open the socket. */ /* The socket command returns a negative number if it fails. * It is typical C programming style to build something and * test its value in one line. */ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) { /* Print an error. When a system call fails, you can use * perror to print your own message plus a system message. */ perror("failed to create socket"); exit(3); } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("failed to connect"); /* We've opened the socket, so it's a good policy to close it. */ close(s); exit(4); } /* VI. Main loop: Get and send lines of text. */ /* fgets(char *str, int n, FILE *source) reads n-1 * characters from the source and stores them in the * string. It also stops when it hits a new-line or * end of file. In general, fgets returns str. If you're * at the end of the file, it returns null, which we've already * seen can be treated as false. * Here you also see a typical C programming techinique; * we're using the return value from fgets to determine whether * or not the loop should continue. */ while (fgets(buf, sizeof(buf), stdin)) { /* This sets the last character to the null character. * I'm not sure why this is necessary. */ buf[MAX_LINE-1] = '\0'; /* Since the string may have ended early (e.g., with a carriage * return), we get the length. */ len = strlen(buf) + 1; /* And we send everything. */ send(s, buf, len, 0); } /* while */ /* VII. We're done. Clean up and exit. */ close(s); exit(0); } /* main() */