Программные каналы
Упражнение 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.