/* Номер порта, который обслуживается сервером */
#define PORTNUM 1500
main (argc, argv)
char *argv[];
int argc;
{
int s;
int pid;
int i, j;
struct sockaddr_in serv_addr;
struct hostent *hp;
char buf[80]="Hello, World!";
/* В качестве аргумента клиенту передается доменное имя
хоста, на котором запущен сервер. Произведем трансляцию
доменного имени в адрес */
if ((hp = gethostbyname(argv[1])) == 0) {
perror("Ошибка вызова gethostbyname()");
exit(3);
}
bzero(&serv_addr, sizeof(serv_addr));
bcopy(hp->h_addr, &serv_addr.sin_addr, hp->h_length);
serv_addr.sin_family = hp->h_addrtype;
serv_addr.sin_port = htons(PORTNUM);
/* Создадим сокет */
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("Ошибка вызова socket!)");
exit(1);
}
fprintf(stderr, "Адрес клиента: %sn",
inet_ntoa(serv_addr.sin_addr));
/* Создадим виртуальный канал */
if (connect (s, (struct sockaddr*)&serv_addr,
sizeof(serv_addr)) == -1) {
perror("Ошибка вызова connect()");
exit(1);
}
/* Отправим серверу сообщение и получим его обратно */
send(s, buf, sizeof(buf), 0);
if (recv(s, buf, sizeof(buf) , 0) < 0) {
perror("Ошибка вызова recv()");
exit(1);
}
/* Выведем полученное сообщение на экран */
printf("Получено от сервера: %sn", buf);
close(s);
printf("Клиент завершил работу nn");
}
Программный интерфейс TLI
При обсуждении реализации сетевой поддержки в BSD UNIX был рассмотрен программный интерфейс доступа к сетевым ресурсам, основанный на сокетах. В данном разделе описан интерфейс транспортного уровня (Transport Layer Interface, TLI), который обеспечивает взаимодействие прикладных программ с транспортными протоколами.
TLI был впервые представлен в UNIX System V Release 3.0 в 1986 году. Этот программный интерфейс тесно связан с сетевой подсистемой UNIX, основанной на архитектуре STREAMS, изолируя от прикладной программы особенности сетевой архитектуры. Вместо того чтобы непосредственно пользоваться общими функциями STREAMS, рассмотренными в предыдущей главе, TLI позволяет использовать специальный набор вызовов, специально предназначенных для сетевых приложений. Для преобразования вызовов TLI в функции интерфейса STREAMS используется библиотека TLI, которая в большинстве систем UNIX имеет название libnsl.a или libnsl.so.
Схема использования функций TLI во многом сходна с рассмотренным интерфейсом сокетов и зависит от типа используемого протокола — с предварительным установлением соединения (например, TCP) или без него (например, UDP).
На рис. 6.18 и 6.19 представлены схемы использования функций TLI для транспортных протоколов с предварительным установлением соединения и без установления соединения. Можно отметить, что эти схемы очень похожи на те, с которыми мы уже встречались в разделе "Межпроцессное взаимодействие в BSD UNIX. Сокеты" главы 3 при обсуждении сокетов. Некоторые различия отмечены ниже при описании функций TLI.
Рис. 6.18. Схема вызова функций TLI для протокола с предварительным установлением соединения
Рис. 6.19. Схема вызова функций TLI для протокола без предварительного установления соединения
Прежде чем перейти к обсуждению функций TLI, остановимся на определении адреса коммуникационного узла. TLI не накладывает никаких ограничений на формат адреса, возлагая интерпретацию на протоколы нижнего уровня. Благодаря этому, один и тот же интерфейс может быть использован при работе с различными семействами сетевых протоколов.
Для определения адреса TLI предоставляет общую структуру данных
netbuf
, имеющую вид:
struct netbuf {
unsigned int maxlen;
unsigned int len;
char *buf;
}
Поле
buf
указывает на буфер, в котором может передаваться адрес узла,
maxlen
определяет его размер, a
len
— количество данных в буфере, т.е. размер адреса. Эта структура по своему назначению похожа на структуру
sockaddr
, которая является общим определением адреса коммуникационного узла для сокетов. Далее рассматривается пример сетевого приложения, основанного на TLI, где показано, как
netbuf
используется при передаче адреса для протоколов TCP/IP.
Структура
netbuf
используется в TLI для хранения не только адреса, но и другой информации — опций протокола и прикладных данных. Эта структура является составной частью более сложных структур данных, используемых при передаче параметров в функциях TLI. Для упрощения динамического размещения этих структур библиотека TLI предоставляет две функции:
t_alloc(3N) для размещения структуры и
t_free(3N) для освобождения памяти. Эти функции имеют следующий вид:
#include <tiuser.h>