/** * В.Д.Валединский * Простейший пример TCP клиента и сервера. * * Файлы * cli_tcp.cpp - пример TCP клиента * ser_tcp_select.cpp - пример TCP сервера c использованием select() * ser_tcp_poll.cpp - пример TCP сервера c использованием poll() * ser_tcp_fork.cpp - пример TCP сервера c использованием fork() * ser_tcp_prefork.cpp - пример TCP сервера c использованием fork() * * Клиент в цикле получает с клавиатуры текстовую строку и отсылает * ее на сервер, читает и выводит на экран ответ сервера. * Сервер ждет соединений от клиентов. При установленом * соединении получает строку от клиента, переводит ее в верхний * регистр и отсылает обратно клиенту. Если клиент постылает строку * содержащую слово stop, то сервер закрывает соединение с этим клиентом, * а клиент заканчивает свою работу. * Клиент и сервер печатают на экран протокол своей работы т.е. * разные данные, которые они получают или отсылают. * * Для ясности примеры составлены максимально просто и не анализируют * некорректные ответы и запросы клиента и сервера, возможность переполнения * буферов ввода вывода, неожиданное 'падение' сервера и т.п. * */ #include #include #include #include #include #include #include #include #include #include #include #include // Определимся с номером порта и другими константами. #define PORT 5555 #define BUFLEN 512 #define NUM_PROC 4 // функции для чтения/записи (см. ниже) bool readFromClient(int fd, char *buf); bool writeToClient (int fd, char *buf); bool ProcessClientRequest (int cli_socket); void WorkWithClients (int sock); int main (void) { int err, opt=1; int sock; struct sockaddr_in addr; // Создаем TCP сокет для приема запросов на соединение sock = socket (PF_INET, SOCK_STREAM, 0); if ( sock<0 ) { perror ("Server: cannot create socket"); exit (EXIT_FAILURE); } setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char*)&opt,sizeof(opt)); // Заполняем адресную структуру и // связываем сокет с любым адресом addr.sin_family = AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); err = bind(sock,(struct sockaddr*)&addr,sizeof(addr)); if ( err<0 ) { perror ("Server: cannot bind socket"); exit (EXIT_FAILURE); } // Создаем очередь на 3 входящих запроса соединения err = listen(sock,3); if ( err<0 ) { perror ("Server: listen queue failure"); exit(EXIT_FAILURE); } // запускаем несколько независимых процессов обслуживания клиентов pid_t pid; for (int ip = 0; ip < NUM_PROC && (pid = fork()) > 0; ip++); if (pid == 0) { // порожденный процесс - обслуживание клиентов WorkWithClients(sock); return 0; } else { // родительский процесс - ожидание завершения порожденных процессов while(wait(0)>0); } return 0; } void WorkWithClients (int sock) { sockaddr_in cli_addr; unsigned int size; int new_sock; while (true) { size = sizeof(sockaddr_in); new_sock = accept(sock,(struct sockaddr*)&cli_addr, &size); if ( new_sock<0 ) { perror("accept"); exit (EXIT_FAILURE); } while ( ProcessClientRequest(new_sock) ); } } bool ProcessClientRequest (int cli_socket) { char buf[BUFLEN]; if ( !readFromClient (cli_socket, buf) ) { printf("read error: connection is closed\n"); close(cli_socket); return false; } if (strstr(buf, "stop")) { printf("client asks to close connection\n"); close(cli_socket); return false; } if ( !writeToClient (cli_socket, buf) ) { printf("write error: connection is closed\n"); close(cli_socket); return false; } return true; } bool readFromClient (int fd, char *buf) { int nbytes; nbytes = read(fd,buf,BUFLEN); if ( nbytes<0 ) { perror ("Server: read failure"); return false; } else if ( nbytes==0 ) { return false; } else { fprintf(stdout,"Server gets message: %s\n",buf); return true; } } bool writeToClient (int fd, char *buf) { int nbytes; unsigned char *s; // ответ переводим в верхний регистр for (s=(unsigned char*)buf; *s; s++) *s = toupper(*s); // отправляем клиенту nbytes = write(fd,buf,strlen(buf)+1); fprintf(stdout,"Write back: %s\nnbytes=%d\n",buf,nbytes); if ( nbytes<0 ) { perror ("Server: write failure"); return false; } return true; }