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

       

Программные каналы


Упражнение 13.57. Напишите программу, определяющую, возвращает ли fstat количество байт в FIFO в качестве поля size структуры tstat.

uses linux;

var

  s:tstat;

 

begin

  if paramcount<>1 then

  begin

    writeln('Используйте: ',paramstr(0),' имя_файла');

    exit;

  end;

  if not fstat(paramstr(1),s) then

  begin



    writeln('Ошибка вызова stat для файла ',paramstr(1));

    exit;

  end;

  writeln('Размер файла ',paramstr(1),' равен ',s.size);

end.

 

Упражнение 13.58. Напишите программу для определения того, что возвращает функция select при проверке возможности записи в дескриптор канала, у которого закрыт второй конец.

uses linux;

var

  fds:fdset;

  fdin,fdout,ret:longint;

 

begin

  if not assignpipe(fdin,fdout) then

  begin

    writeln('Ошибка создания программного канала');

    exit;

  end;

  fd_zero(fds);

  fd_set(fdin,fds);

  fd_set(fdout,fds);

  fdwrite(fdout,'Некая достаточно длинная строка',31);

  fdclose(fdin);

  writeln('Вызов select');

  ret:=select(2,nil,@fds,nil,1000);

  writeln('select вернул ',ret);

end.

 

Упражнение 13.59. Используя канал между родителем (клиентом) и потомком (сервером), создайте программу, в которой клиент считывает имя файла из стандартного ввода и записывает в канал. Если файл существует, сервер считывает его и записывает в канал, в противном случае возвращает клиенту сообщение об ошибке.

uses linux,sysutils;

const

  BLOCKSIZE=1024;

var

  pid,(*идентификатор процесса*)

  filesize,(*размер файла*)

  fd,(*дескриптор файла*)

  kol,(*количество прочитанных байт*)

  i:longint;

  in1,out1,in2,out2:longint;(*дескрипторы программных каналов*)

  filename:string[80];

  st:tstat;(*для получения информации о размере файла*)

  buf:array[0..BLOCKSIZE-1]of char;(*буфер чтения-записи*)

begin

  (*попытка создания двух программных каналов*)

  if not assignpipe(in1,out1) then

  begin

    writeln('Ошибка создания первого программного канала');




    exit;

  end;

 

  if not assignpipe(in2,out2) then

  begin

    writeln('Ошибка создания второго программного канала');

    fdclose(in1); (*закрываем ранее созданный канал 1*)

    fdclose(out1);

    exit;

  end;

 

  pid:=fork; (*клонирование процесса*)

 

  if pid=-1 then (*ошибка клонирования*)

  begin

    writeln('Ошибка создания потомка');

    exit;

  end;

  if pid=0 (*сервер - потомок*) then (*ветка потомка*)

  begin

    fdclose(out1);(* закрываем для надежности ненужные каналы:

                    первый - для записи, второй - для чтения*)

    fdclose(in2);

    fdread(in1,filename,80); (*читаем из первого канала имя файла*)

    {}writeln('Сервер: получено имя файла - ',filename);

    if access(filename,f_ok or r_ok) then (*если файл существует и доступен для чтения*)

    begin

      fstat(filename,st);(*получем информацию о файле*)

      filesize:=st.size; (*узнаем размер файла*)

      {}writeln('Сервер: определен размер файла - ',filesize);

      fdwrite(out2,filesize,sizeof(filesize)); (*пишем во второй канал размер файла*)

      {}writeln('Сервер: размер файла записан в канал');

      fd:=fdopen(filename,Open_RDONLY);(*открываем файл для чтения*)

      i:=1;

      kol:=fdread(fd,buf,BLOCKSIZE); (*читаем блоками по BLOCKSIZE байт*)

      while kol>0 do

      begin

        fdwrite(out2,buf,kol); (*пишем во второй канал столько, сколько прочли из файла*)

        {}writeln('Сервер: записано в канал ',i*kol/BLOCKSIZE:1:1,' Kb');

        kol:=fdread(fd,buf,BLOCKSIZE);

      end;

      fdclose(fd);(*закрываем файл*)

      {}writeln('Сервер: файл записан в канал');

    end

    else (*если файл не существует или недоступен для чтения*)

    begin

      filesize:=-1; (*записываем в программный канал признак ошибки*)

      fdwrite(out2,filesize,sizeof(filesize));

    end;

    {}writeln('Сервер: работа завершена');

    halt(0); (*завершаем работу потомка*)

  end

  else     (*клиент - родитель*)  (*ветка родителя*)

  begin



    fdclose(in1); (* закрываем ненужные каналы: первый для чтения, второй - для записи*)

    fdclose(out2);

    write('Введите имя файла: '); (*запрос имени файла*)

    readln(filename);

    fdwrite(out1,filename,80); (*пишем имя в программный канал*)

    {}writeln('Клиент: имя файла записано в канал');

    fdread(in2,filesize,sizeof(filesize)); (*получем размер файла из канала*)

    {}writeln('Клиент: из канала получен размер файла - ',filesize);

    if in2=-1 then (*при ошибке*)

      writeln('Файл ',filename,' не существует или недоступен для чтения')

    else

    begin

      (*создаем файл*)

      {}writeln('Клиент: файл создан, идет прием');

      for i:=length(filename) downto 1 do

        if filename[i]='/' then

        begin

          delete(filename,1,i);

          break;

        end;

      fd:=fdopen(filename,Open_WRONLY or Open_CREAT or Open_TRUNC, octal(644));

      if fd=-1 then

      begin

        writeln('Ошибка создания файла ',filename);

        kill(pid,9);

        halt(1);

      end;

     

      for i:=1 to filesize do(*пока есть что читать из канала*)

      begin

        fdread(in2,buf,1);

        if i mod BLOCKSIZE=0 then

        {}writeln('Клиент: записано в файл ',i div BLOCKSIZE,' Kb');

        fdwrite(fd,buf,1);(*записываем в файл*)

      end;

      fdclose(fd);(*закрываем созданный файл*)

      {}writeln('Клиент: файл закрыт');

    end;

    waitpid(pid,nil,0); (*ожидаем завершения потомка*)

    {}writeln('Клиент: сервер завершен, конец работы');

  end;

end.

Упражнение 13.60. Используя popen, создайте канал между who и more.

uses linux;

var

  f1,f2:text;

  s:string;

begin

  popen(f1,'who','r');

  if linuxerror <> 0 then

  begin

    writeln('Ошибка открытия канала с who для чтения');

    exit;

  end;

  popen(f2,'more','w');

  if linuxerror <> 0 then

  begin

    writeln('Ошибка открытия канала с more для записи');

    exit;

  end;

  while not eof(f1) do

  begin

    readln(f1,s);

    writeln(f2,s);

  end;

  pclose(f1);

  pclose(f2);

end.


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