Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

10.5.4. Подключение клиента

Для выполнения запроса на подключение к серверному процессу клиент использует системный вызов connect.

Описание

uses sockets;

Function Connect(csockfd:Longint; Var address; add_len:Longint): Longint;

Function Connect(csockfd:longint; const address:string;

var SockIn,SockOut:text):Boolean;

Function Connect(csockfd:longint; const address:string;

var SockIn,SockOut:file):Boolean;

Function Connect(csockfd:longint; const address:TInetSockAddr;

var SockIn,SockOut:file):Boolean;

Первый параметр csockfd является дескриптором сокета клиента и не имеет отношения к дескриптору сокета на сервере. Параметр address указывает на структуру, содержащую адрес сервера, либо на адрес в формате строки. Параметр add_len определяет размер используемой структуры адреса.

Вторая, третья и четвертая формы вызова connect эквивалентны вызову первой с последующим использованием функции Sock2Text, преобразующей сокет sockfd в две файловые переменные типа Text, одна из которых отвечает за чтение из сокета (SockIn), а другая – за запись в сокет (SockOut).

Продолжая составление рассматриваемого примера, запишем следующий вариант текста программы клиента:

(* Клиентский процесс *)

uses sockets,stdio,linux;

const

SIZE=sizeof(tinetsockaddr);

server:tinetsockaddr=(family:AF_INET; port:7000);

var

sockfd:longint;

begin

(* Преобразовать и сохранить IP address сервера *)

server.addr := inet_addr ('127.0.0.1');

(* Создать сокет *)

sockfd := socket (AF_INET, SOCK_STREAM, 0);

if sockfd = -1 then

begin

perror ('Ошибка вызова socket');

halt (1);

end;

(* Соединяет сокет с сервером *)

if not connect (sockfd, server, SIZE) then

begin

perror ('Ошибка вызова connect');

halt (1);

end;

(* Обмен данными с сервером *)

end.

Адрес сервера преобразуется в нужный формат при помощи вызова inet_addr. Адреса известных компьютеров локальной сети обычно можно найти в файле /etc/hosts.

10.5.5. Пересылка данных

Теперь уже освоена процедура установления соединения между клиентом и сервером. Для сокетов типа SOCK_STREAM и клиент, и сервер получают дескрипторы файлов, которые могут использоваться для чтения или записи. В большинстве случаев для этого годятся обычные вызовы fdread и fdwrite. Если же необходимо задавать дополнительные параметры пересылки данных по сети, то можно использовать два новых системных вызова – send и recv. Эти вызовы имеют схожий интерфейс и ведут себя точно так же, как вызовы fdread и fdwrite, если их четвертый аргумент равен нулю.

Описание

uses sockets;

Function Recv(sockfd:Longint; Var buffer; length,Flags:Longint):Longint;

Function Send(sockfd:Longint; Var buffer; length,Flags:Longint):Longint;

Вызов recv имеет четыре параметра: дескриптор файла filedes, из которого читаются данные, буфер buffer, в который они помещаются, размер буфера length и поле флагов flags.

Параметр flags указывает дополнительные опции получения данных. Его возможные значения определяются комбинациями следующих констант:

MSG_PEEK

Процесс может просматривать данные, не «получая» их

MSG_OOB

Обычные данные пропускаются. Процесс принимает только срочные данные, например, сигнал прерывания

MSG_WAITALL

Возврат из вызова recv произойдет только после получения всех данных

При аргументе flags равном нулю вызов send работает точно так же, как и вызов write, пересылая массив данных буфера buffer в сокет sockfd. Параметр length задает размер массива данных. Аналогично вызову recv параметр flags определяет опции передачи данных. Его возможные значения определяются комбинациями следующих констант:

MSG_OOB

Передать срочные (out of band) данные

MSG_DONTROUTE

При передаче сообщения игнорируются условия маршрутизации протокола более низкого уровня. Обычно это означает, что сообщение посылается по прямому, а не по самому быстрому маршруту (самый быстрый маршрут не обязательно прямой и может зависеть от текущего распределения нагрузки сети)

Теперь с помощью этих вызовов можно реализовать обработку данных на серверной стороне:

(* Серверный процесс *)

var

c:char;

client:tinetsockaddr;

clientaddrlen:longint;

begin

(* Приведенная выше инициализация сокета *)

.

.

.

while true do

begin

(* Принимает запрос на установку соединения *)

newsockfd := accept (sockfd, client, clientaddrlen);

if newsockfd = -1 then

begin

perror ('Ошибка вызова accept');

continue;

end;

(* Создает дочерний процесс для работы с соединением *)

if fork = 0 then

begin

(* Принимает данные *)

while recv (newsockfd, c, 1, 0) > 0 do

begin

(* Преобразовывает строчный символ в прописной *)

c := upcase (c);

(* Пересылает символ обратно *)

send (newsockfd, c, 1, 0);

end;

end;

end;

end.

Напомним, что использование вызова fork позволяет серверу обслуживать несколько клиентов. Цикл работы клиентского процесса может быть реализован так:

(* Клиентский процесс *)

var

sockfd:longint;

c,rc:char;

begin

(* Приведенная выше инициализация сокета и запрос

* на установку соединения *)

(* Обмен данными с сервером *)

rc := #$a;

while true do

begin

if rc = #$a then

writeln ('Введите строчный символ');

c:=char(getchar);

send (sockfd, c, 1, 0);

recv (sockfd, rc, 1, 0);

write (rc)

end;

end.

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal