Системное программирование в UNIX средствами Free Pascal

Если параметр send_addr равен nil,


uses stdio;
function recvfrom(sockfd:longint; var message; length, flags:longint;
                  var send_addr:tsockaddr; var add_len:longint):longint;
function sendto(sockfd:longint; var message; length, flags:longint;
                var dest_addr:tsockaddr; dest_len:longint):longint;
Если параметр send_addr равен nil, то вызов recvfrom работает точно так же, как и вызов recv. Параметр message указывает на буфер, в который помещается принимаемая дейтаграмма, а параметр length задает число байтов, которые должны быть считаны в буфер. Параметр flags принимает те же самые значения, что и в вызове recv. Два последних параметра помогают установить двустороннюю связь с помощью UDP-сокета. В структуру send_addr будет помещена информация об адресе и порте, откуда пришел прочитанный пакет. Это позволяет принимающему процессу направить ответ пославшему пакет процессу. Последний параметр является указателем на целочисленную переменную типа longint, в которую помещается длина записанного в структуру send_addr адреса.
Вызов sendto противоположен вызову recvfrom. В этом вызове параметр dest_addr задает адрес узла сети и порт, куда должно быть передано сообщение, а параметр dest_len определяет длину адреса.
Адаптируем пример для модели дейтаграммных посылок.
(* Сервер *)
uses sockets,linux,stdio;
const
  SIZE=sizeof(tinetsockaddr);
  (* Локальный серверный порт *)


  server:tinetsockaddr = (family:AF_INET; port:7000; addr:INADDR_ANY);
  client_len:longint=SIZE;
var
  sockfd:longint;
  c:char;
  (* Структура, которая будет содержать адрес процесса 2 *)
  client:tinetsockaddr;
begin
  (* Установить абонентскую точку сокета *)
  sockfd := socket (AF_INET, SOCK_DGRAM, 0);
  if sockfd = -1 then
  begin
    perror ('Ошибка вызова socket');
    halt (1);
  end;
  (* Связать локальный адрес с абонентской точкой *)
  if not bind (sockfd, server, SIZE) then
  begin
    perror ('Ошибка вызова bind');
    halt (1);


  end;
  (* Бесконечный цикл ожидания сообщений *)
  while true do
  begin
    (* Принимает сообщение и записывает адрес клиента *)
    if recvfrom (sockfd, c, 1, 0, tsockaddr(client), client_len) = -1 then
    begin
      perror ('Сервер: ошибка при приеме');
      continue;
    end;
    c := upcase (c);
    (* Посылает сообщение обратно *)
    if sendto (sockfd, c, 1, 0, tsockaddr(client), client_len) = -1 then
    begin
      perror ('Сервер: ошибка при передаче');
      continue;
    end;
  end;
end.
Новый текст клиента:
(* Клиентский процесс *)
uses sockets,stdio,linux;
const
  SIZE=sizeof(tinetsockaddr);
 
  (* Локальный порт на клиенте *)
  client:tinetsockaddr = (family:AF_INET; port:INADDR_ANY; addr:INADDR_ANY);
  (* Адрес удаленного сервера *)
  server:tinetsockaddr = (family:AF_INET; port:7000);
var
  sockfd:longint;
  c:char;
begin
  (* Преобразовать и записать IP адрес *)
  server.addr := inet_addr ('127.0.0.1');
  (* Установить абонентскую точку сокета *)
  sockfd := socket (AF_INET, SOCK_DGRAM, 0);
  if sockfd = -1 then
  begin
    perror ('Ошибка вызова socket');
    halt (1);
  end;
  (* Связать локальный адрес с абонентской точкой сокета. *)
  if not bind (sockfd, client, SIZE) then
  begin
    perror ('Ошибка вызова bind');
    halt (1);
  end;
  (* Считать символ с клавиатуры *)
  while fdread (0, c, 1) <> 0 do
  begin
    (* Передать символ серверу *)
    if sendto (sockfd, c, 1, 0, tsockaddr(server), SIZE) = -1 then
    begin
      perror ('Клиент: ошибка передачи');
      continue;
    end;
    (* Принять вернувшееся сообщение *)
    if recv (sockfd, c, 1, 0) = -1 then
    begin
      perror ('Клиент: ошибка приема');
      continue;
    end;
    fdwrite (1, c, 1);
  end;
end.
Упражнение 10.4. Запустите сервер и несколько клиентов. Как сервер определяет, от какого клиента он принимает сообщение?

Содержание раздела