UNIX: разработка сетевых приложений
Часть 49 из 399 Информация о книге
Для каждого клиента функция19-24порождает дочерний процесс, и дочерний процесс обслуживает запрос этого клиента. Как мы говорили в разделе 4.8, дочерний процесс закрывает прослушиваемый сокет, а родительский процесс закрывает присоединенный сокет. Затем дочерний процесс вызывает функциюfork(см. листинг 5.2) для обработки запроса клиента.str_echo5.3. Эхо-сервер TCP: функция str_echo
Функция
, показанная в листинге 5.2, выполняет серверную обработку запроса клиента: считывание строк от клиента и отражение их обратно клиенту.str_echoЛистинг 5.2. Функция str_echo: отраженные строки на сокете
//lib/str_echo.c1 #include "unp.h"2 void3 str_echo(int sockfd)4 {5 ssize_t n;6 char buf[MAXLINE];7 for (;;) {8 if ((n = read(sockfd, buf, MAXLINE)) > 0)9 return; /* соединение закрыто с другого конца */10 Writen(sockfd, line, n);11 }12 }Чтение строки и ее отражениеФункция7-11считывает очередную строку из сокета, после чего строка отражается обратно клиенту с помощью функцииread. Если клиент закрывает соединение (нормальный сценарий), то при получении клиентского сегмента FIN функция дочернего процессаwritenвозвращает нуль. После этого происходит возврат из функцииreadи далее завершается дочерний процесс, приведенный в листинге 5.1.str_echo5.4. Эхо-клиент TCP: функция main
В листинге 5.3 показана функция
TCP-клиента.mainЛистинг 5.3. Эхо-клиент TCP
//tcpcliserv/tcpcli01.c1 #include "unp.h"2 int3 main(int argc, char **argv)4 {5 int sockfd;6 struct sockaddr_in servaddr;7 if (argc != 2)8 err_quit("usage: tcpcli <Ipaddress>");9 sockfd = Socket(AF_INET, SOCK_STREAM, 0);10 bzero(&servaddr. sizeof(servaddr));11 servaddr.sin_family = AF_INET;12 servaddr.sin_port = htons(SERV_PORT);13 Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);14 Connect(sockfd, (SA*)&servaddr, sizeof(servaddr));15 str_cli(stdin, sockfd); /* эта функция выполняет все необходимыедействия со стороны клиента */16 exit(0);17 }Создание сокета, заполнение структуры его адресаСоздается сокет TCP и структура адреса сокета заполняется IP-адресом сервера и номером порта. IP-адрес сервера мы берем из командной строки, а известный номер порта сервера (9-13) — из нашего заголовочного файлаSERV_PORT.unp.hСоединение с серверомФункция14-15устанавливает соединение с сервером. Затем функцияconnect(см. листинг 5.4) выполняет все необходимые действия со стороны клиента.str_cli5.5. Эхо-клиент TCP: функция str_cli
Эта функция, показанная в листинге 5.4, обеспечивает отправку запроса клиента и прием ответа сервера в цикле. Функция считывает строку текста из стандартного потока ввода, отправляет ее серверу и считывает отраженный ответ сервера, после чего помещает отраженную строку в стандартный поток вывода.
Листинг 5.4. Функция str_cli: цикл формирования запроса клиента
//lib/str_cli.c1 #include "unp.h"2 void3 str_cli(FILE *fp, int sockfd)4 {5 char sendline[MAXLINE], recvline[MAXLINE];6 while (Fgets(sendline, MAXLINE, fp) != NULL) {7 Writen(sockfd,. sendline, strlen(sendline));8 if (Readline(sockfd, recvline, MAXLINE) == 0)9 err_quit("str_cli: server terminated prematurely");10 Fputs(recvline, stdout);11 }12 }Считывание строки, отправка серверуФункция6-7считывает строку текста, а функцияfgetsотправляет эту строку серверу.writenСчитывание отраженной сервером строки, запись в стандартный поток выводаФункция8-10принимает отраженную сервером строку, а функцияreadlineзаписывает ее в стандартный поток вывода.fputsВозврат в функцию mainЦикл завершается, когда функция11-12возвращает пустой указатель, что означает достижение конца файла или обнаружение ошибки. Наша функция-оберткаfgetsпроверяет наличие ошибки, и если ошибка действительно произошла, прерывает выполнение программы. Таким образом, функцияFgetsвозвращает пустой указатель только при достижении конца файла.Fgets