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

 ssize_t number_characters_read;

 /* Отправка HTTP-команды GET с запросом начальной страницы. */

 sprintf(buffer, "GET /\n");

 write(socket_fd, buffer, strlen(buffer));

 /* Чтение данных из сокета. Функция read() может вернуть

    не все данные сразу, поэтому продолжаем чтение, пока

    не будут получены все данные. */

 while (1) {

  number_characters_read = read(socket_fd, buffer, 10000);

  if (number_characters_read == 0)

   return;

  /* Запись данных в стандартный выходной поток. */

  fwrite(buffer, sizeof(char), number_characters_read, stdout);

 }

}

int main(int argc, char* const argv[]) {

 int socket_fd;

 struct sockaddr_in name;

 struct hostent* hostinfo;

 /* Создание сокета. */

 socket_fd = socket(PF_INET, SOCK_STREAM, 0);

 /* Запись имени сервера в адресную структуру. */

 name.sin_family = AF_INET;

 /* Преобразование адреса из текстового представления во

    внутреннюю форму. */

 hostinfo = gethostbyname(argv[1]);

 if (hostinfo == NULL)

  return 1;

 else

  name sin_addr = *((struct in_addr*)hostinfo->h_addr);

 /* Web-серверы используют порт 80. */

 name.sin_port = htons(80);

 /* Подключаемся к Web-серверу. */

 if (connect(socket_fd, &name,

  sizeof(struct sockaddr_in)) == -1) {

  perror("connect");

  return 1;

 }

 /* получаем содержимое начальной страницы сервера. */

 get_home_page(socket_fd);

 return 0;

}

Программа извлекает имя Web-сервера из командной строки (имя не является URL-адресом, т.е. в нем отсутствует префикс http://). Далее вызывается функция gethostbyname(), которая преобразует имя сервера в числовое представление. После этого программа подключает потоковый (TCP) сокет к порту 80 сервера. Web-серверы общаются по протоколу HTTP (Hypertext Transfer Protocol), поэтому программа посылает HTTP-команду GET, в ответ на которую сервер возвращает текст начальной страницы.

Стандартные номера портов

По существующему соглашению Web-серверы ожидают поступления запросов на порт 80. За большинством lntemet-сервисов закреплены стандартные номера портов. Например, защищенные Web-серверы работающие по протоколу SSL. прослушивают порт 443 а почтовые серверы (протокол SMTP) прослушивают порт 25

В Linux связи между именами протоколов/сервисов и номерами портов устанавливаются в файле /etc/services. В первой колонке файла указано имя протокола или сервисе. Во второй колонке приведен номер порта и тип взаимодействия: tcp — для сервисов ориентированных на соединения, и udp — для дейтаграмм.

При реализации собственных сетевых сервисов используйте номере портов, большие чем 1024

Например, чтобы получить начальную страницу с сервера www.codesourcery.com, введите следующую команду:

% ./socket-inet www.codesourcery.com

<html>

 <meta http-equiv="Content-Type"

  content="text/html; charset=iso-8859-1">

...

5.5.7. Пары сокетов

Как было показано выше, функция pipe() создает два дескриптора для входного и выходного концов канала. Возможности каналов ограничены, так как с файловыми дескрипторами должны работать связанные процессы и данные через канал передаются только в одном направлении. Функция socketpair() создает два дескриптора для двух связанных сокетов, находящихся на одном компьютере. С помощью этих дескрипторов можно организовать двунаправленное взаимодействие процессов.

Первые три параметра функции socketpair() такие же, как и в функции socket(): пространство имен (должно быть PF_LOCAL), тип взаимодействия и протокол. Последний параметр — это массив из двух целых чисел, куда будут записаны дескрипторы сокетов, подобно функции pipe().

Часть II

Секреты Linux

Глава 6

Устройства

Linux, как и большинство операционных систем, взаимодействует с аппаратными устройствами посредством модульных программных компонентов, называемых драйверами. Драйвер скрывает от операционной системы детали взаимодействия с устройством и предоставляет в распоряжение системы стандартный интерфейс обращения к устройству.

В Linux драйверы устройств являются частью ядра и могут подключаться к ядру статически либо по запросу в виде модулей. Драйверы недоступны напрямую пользовательским процессам. Но в Linux имеется особый механизм — специальные файловые объекты, позволяющие процессам взаимодействовать с драйверами, а через них — с аппаратными устройствами. Такие объекты являются частью операционной системы, поэтому программы могут открывать их, читать из них данные и осуществлять запись в них точно так же, как если бы это быта обычные файлы. С помощью низкоуровневых вызовов (описаны в приложении Б, "Низкоуровневый ввод-вывод") или стандартных библиотечных функций ввода-вывода программы могут обмениваться данными с устройствами через файловые объекты