3. Запрашивать связывание, при котором в TCB копируется локальный адрес socket.

4. Создавать очередь, которая сможет хранить сведения о пяти клиентах. Оставшиеся шаги повторяются многократно:

5. Ожидать запросов от клиентов. Когда появляется клиент, создавать для него новый TCB на основе копии главного TCB и записи в него адреса socket клиента и других параметров.

6. Создавать дочерний процесс для обслуживания клиента. Дочерний процесс будет наследовать новый TCB и обрабатывать все дальнейшие операции по связи с клиентом

(ожидать сообщений от клиента, записывать их и завершать работу).

Каждый шаг в программе объясняется в следующем разделе.

/* tcpserv.c

 * Для запуска программ ввести 'tcpserv'. */

/* Сначала включить набор стандартных заголовочных файлов. */

#include <sys/types.h>

#include <sys/socket.h>

#include <stdio.h>

#include <netinet/in.h>

#include <netdb.h>

#include <errno.h>

main() {

 int sockMain, sockClient, length, child;

 struct sockaddr_in servAddr;

 /* 1. Создать главный блок управления пересылкой. */

 if ((sockMain = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

  perror('Сервер не может открыть главный socket.');

  exit(1);

 }

 /* 2. Создать структуру данных для хранения локальных IP-адресов

  * и портов, которые будут использованы. Предполагается прием

  * клиентских соединений от любых локальных IP-адресов

  * (INADDR_ANY). Поскольку данный сервер не применяет

  * общеизвестный порт, установить port = 0. Это позволит

  * связать вызов с присвоением порта серверу и записать

  * порт в TCB. */

 bzero((char *)&servAddr, sizeof(servAddr));

 servAddr.sin_family = AF_INET;

 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

 servAddr.sin_port = 0;

 /* 3. Связать запрос, выбор номера порта и

  * запись его в TCB. */

 if (bind(sockMain, &servAddr, sizeof(servAddr))) {

  perror('Связывание сервера неудачно.');

  exit(1);

 }

 /* Чтобы увидеть номер порта, следует использовать

  * функцию getsockname(), чтобы скопировать порт в servAddr. */

 length = sizeof(servAddr);

 if (getsockname(sockMain, &servAddr, &length)) {

  perror('Вызов getsockname неудачен.');

  exit(1);

 }

 printf('СЕРВЕР: номер порта - %d ', ntohs(servAddr.sin_port));

 /* 4. Создать очередь для хранения пяти клиентов. */

 listen(sockMain, 5);

 /* 5. Ожидать клиента. При разрешении возвратить новый

  * дескриптор socket, который должен использоваться клиентом. */

 for(;;) {

  if ((sockClient = accept(sockMain, 0, 0)) < 0) {

   perror ('Неверный socket для клиента.');

   exit(1);

  }

  /* 6. Создать дочерний процесс для обслуживания клиента. */

  if ((child = fork()) < 0) {

   perror('Ошибка создания дочернего процесса.');

   exit(1);

  } else if (child == 0) /* Это код для исполнения дочернего процесса. */

  {

   close(sockMain); /* Дочерний процесс неинтересен для sockMain.*/

   childWork(sockClient);

   close(sockClient);

   exit(0);

  }

  /* 7. Это родительский процесс. Его более не интересует

   * socket клиента, поскольку его обслуживание передано

   * дочернему процессу. Родительский процесс закрывает свой элемент для

   * socket клиента и переходит на цикл приема новых accept(). */

  close(sockClient);

 }

}

/* Дочерний процесс читает один поступивший буфер, распечатывает

 * сообщение и завершается. */

#define BUFLEN 81

int childWork(sockClient)

int sockClient;

{

 char buf[BUFLEN];

 int msgLength;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату