// // A simple Internet client application. // It connects to a remote server, // receives any messages from a server, // prints them on standard output, and // sends to a server all lines that a user prints // on the keyboard. // // The program illustrates the "select" function used to // emulate an "asynchronous" style of work. // // Usage: // asyncli [IP_address_of_server [port_of_server]] // where IP_address_of_server is either IP number of server // or a symbolic Internet name, default is "localhost"; // port_of_server is a port number, default is 1234. // #include #include #include #include #include #include #include #include #include #include #include static void usage(); static void sigHandler(int sigID); // Handler of SIGPIPE signal const int BUFFER_MAXLEN = 512; static char readBuffer[BUFFER_MAXLEN + 2]; static bool finished = false; // Finish the program int main(int argc, char *argv[]) { int s; // Network socket fd_set readfds; // Set of socket descriptors for select struct timeval tv; // Timeout value bool newLine = true; // The last char is '\n' bool pointAtBeginning = false; // The last 2 chars are "\n." // Set signal handler for the "SIGPIPE" signal // (used to intercept the signal about broken connection). if (signal(SIGPIPE, &sigHandler) == SIG_ERR) { perror("Cannot install a signal handler"); exit(1); } if (argc > 1 && *(argv[1]) == '-') { usage(); exit(1); } // Create a socket s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { perror("Cannot create a socket"); exit(1); } // Fill in the address of server struct sockaddr_in peeraddr; memset(&peeraddr, 0, sizeof(peeraddr)); const char* peerHost = "localhost"; if (argc > 1) peerHost = argv[1]; // Resolve the server address (convert from symbolic name to IP number) struct hostent *host = gethostbyname(peerHost); if (host == NULL) { perror("Cannot define host address"); exit(1); } peeraddr.sin_family = AF_INET; short peerPort = 1234; if (argc >= 3) peerPort = (short) atoi(argv[2]); peeraddr.sin_port = htons(peerPort); // Print a resolved address of server (the first IP of the host) printf( "peer addr = %d.%d.%d.%d, port %d\n", host->h_addr_list[0][0] & 0xff, host->h_addr_list[0][1] & 0xff, host->h_addr_list[0][2] & 0xff, host->h_addr_list[0][3] & 0xff, (int) peerPort ); // Write resolved IP address of a server to the address structure memmove(&(peeraddr.sin_addr.s_addr), host->h_addr_list[0], 4); // Connect to a remote server int res = connect(s, (struct sockaddr*) &peeraddr, sizeof(peeraddr)); if (res < 0) { perror("Cannot connect"); exit(1); } printf("Connected. Type a message and press \"Enter\".\n"); printf("To finish, enter a line containing a point only.\n"); while (!finished) { FD_ZERO(&readfds); // Erase the set of socket descriptors FD_SET(0, &readfds); // Add keyboard file descriptor to the set FD_SET(s, &readfds); // Add the socket to the set tv.tv_sec = 0; // Define the timeout value tv.tv_usec = 50000; // 0.05 sec (in microseconds) //=== "select" is the key poit of the program! ============ res = select( s + 1, // Max. number of socket in all sets + 1 &readfds, // Set of socket descriptors for reading NULL, // Set of sockets for writing -- not used NULL, // Set of sockets with exceptions -- not used &tv // Timeout value ); //========================================================= if (res < 0) { perror("Select error"); finished = 1; break; } else if (res == 0) { continue; // No data is availible yet } if (FD_ISSET(0, &readfds)) { // Keyboard character is ready char key[2]; ssize_t len = read(0, key, 1); // printf("Read %d characters from keyboard.\n", int(len)); if (len != 1) // Error reading continue; // go to next command // Exit on single point at beginning of new line if (newLine && key[0] == '.') { pointAtBeginning = true; } else if (key[0] == '\n' && pointAtBeginning) { finished = true; } else { pointAtBeginning = false; } newLine = (key[0] == '\n'); len = write(s, key, 1); if (len < 0) { if (errno != EAGAIN) { perror("Write error"); break; // Write error } else { perror("Could not write to socket"); } } else if (res == 0) { printf("Connection closed"); break; } } else if (FD_ISSET(s, &readfds)) { // Network data is coming ssize_t len = read( s, readBuffer, BUFFER_MAXLEN ); if (len > 0) { readBuffer[len] = 0; printf("%s", readBuffer); } else { if (len < 0 && errno != EAGAIN) { perror("Read error"); finished = 1; } break; } } } // end while shutdown(s, 2); close(s); return 0; } static void usage() { printf( "A simple Internet client application.\n" "Usage:\n" " asyncli [IP_address_of_server [port_of_server]]\n" " where IP_address_of_server is either IP number of server\n" " or a symbolic Internet name, default is \"localhost\";\n" " port_of_server is a port number, default is 1234.\n" "The client connects to a server which address is given in a\n" "command line, receives a messages from a server and sends\n" "to a server all lines that a user prints on a keyboard.\n" ); } static void sigHandler(int /* sigID */) { printf("The SIGPIPE signal (connection is broken).\n"); finished = true; }