Выбрать главу

 char buf[BUFLEN];

 /* 1. Создать socket для UDP. */

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

  perror("Сервер не может открыть socket для UDP.");

  exit(1);

 }

 /* 2. Ввести информацию в структуру данных, используемую для хранения локальных

  * IP-адресов и порта. Возложить на bind получение свободных портов. */

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

 servAddr.sin_family = AF_INET;

 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

 servAddr.sin_port = 0;

 /* 3. Вызвать bind, которая запишет номер используемого порта

  * в TCB. */

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

  perror("Вызов bind от сервера неудачен.");

  exit(1);

 }

 /* 4. Извлекаем номер порта и используем функцию

  * getsockname() для копирования порта в servAddr. */

 addrLength = sizeof(servAddr);

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

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

  exit(1);

 }

 printf("SERVER: Номер порта is %d\n", ntohs(servAddr.sin_port));

 /* 5. Бесконечный цикл ожидания сообщений от клиентов. */

 for (;;) {

  addrLength = sizeof(clientAddr);

  bzero(buf, BUFLEN);

  if ((msgLength = recvfrom(sockMain, buf, BUFLEN, 0, &clientAddr, &addrLength)) < 0) {

   perror("Плохой socket клиента.");

   exit(1);

  }

  /* 6. Распечатать клиентские IP-адрес и порт вместе с сообщением. */

  printf("SERVER: IP-адрес клиента: %s\n",

   inet_ntoa(clientAddr.sin_addr));

  printf("SERVER: Порт клиента: %d\n",

   ntohs(clientAddr.sin_port));

  printf("SERVER: Длина сообщения %d\n", msgLength);

  printf("SERVER: Сообщение: %s\n\n", buf);

 }

}

21.10.1 Вызовы в серверной программе UDP

1. sockMain = socket(AF_NET, SOCK_DGRAM, 0);

Семейство адресов — снова Интернет.

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

servAddr.sin_family = AF_INET;

servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

servAddr.sin_port = 0;

Вызовы инициализации адресной структуры сервера те же, что и в программе для TCP.

3. bind(sockMain, &servAddr, sizeof(servAddr));

Как и прежде, bind получает порт для сервера и записывает значения в TCB. Конечно, по сравнению с TCP, UDP содержит очень мало информации.

4. getsockname(sockMain, &servAddr, &length);

Использовать getsockname, чтобы извлечь присвоенный socket порт.

5. msgLength = recvfrom(sockMain, buf, BUFLEN, 0, &clientAddr, &length);

Вызов recvfrom имеет форму:

recvfrom(дескриптор_socket, входной_буфер, длина_буфера, флаги, исходная_адресная_структура, указатель_на_длину_исходной_адресной_структуры)

Флаги позволяют вызывающей стороне просмотреть сообщение без его фактического получения. После возвращения исходная адресная структура заполняется IP-адресом и номером порта клиента. Необходим указатель на длину исходного адреса, поскольку она может быть изменена при вставке в поле фактического адреса клиента.

6. inet_ntoa(clientAddr.sin_addr);

Этот вызов преобразует 32-разрядный адрес Интернета клиента в знакомую нам нотацию этого адреса с точками и десятичными значениями.

21.11 Клиентская программа UDP

Клиент соединяется с сервером, посылает одно сообщение и закрывает соединение. При запуске программы конечный пользователь должен ввести имя хоста, порт сервера и отправляемое на сервер сообщение. Например:

udpclient plum.cs.yale.edu 2315 "Это сообщение."

/* udpclient.с

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

 * Далее нужно получить порт сервера.

 * Для запуска клиента ввести:

 * udpclient имя_хоста порт сообщение */

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <netdb.h>

#include <stdio.h>

#include <errno.h>

main(argc, argv)

 int argc;

 char *argv[]; /* Это вводимые пользователем аргументы. */

               /* argv[0] - имя программы. argv[1] указывает на имя хоста. */

               /* argv[2] ссылается на порт, */

               /* а argv [3] ссылается на текстовое сообщение. */

{

 int sock;

 struct sockaddr_in, servAddr, clientAddr;

 struct hostent *hp, *gethostbyname();

 /* Должно быть четыре аргумента. */

 if (argc < 4) {

  printf ("ВВЕСТИ udpclient имя_хоста порт сообщение\n");

  exit(1);

 }

 /* 1. Создать socket для UDP. */

 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {

  perror("He получен socket\n");

  exit(1);

 }

 /* 2. Занести адрес и порт сервера в servAddr.

  * Сначала заполнить адресную структуру нулями.

  * Использовать функцию gethostbyname для получения имени хоста

  * и его IP-адреса. Затем скопировать IP-адрес

  * в servAddr функцией bcopy.

  * Наконец занести номер порта из argv[2]. */

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

 servAddr.sin_family = AF_INET;

 hp = gethostbyname(argv[1]);

 bcopy(hp->h_addr, &servAddr.sin_addr, hp->h_length);

 servAddr.sin_port = htons(atoi(argv[2]));

 /* 3. Вызвать bind для получения порта UDP. Система

  * назначает свободный порт. */

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

 clientAddr.sin_family = AF_INET;

 clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);

 clientAddr.sin_port = 0;