Анимация
JavaScript
|
Главная Библионтека 7.14. Асинхронный ввод/вывод 269 Чтобы справиться с этой проблемой, мы последователь}ю читаем по одному символу и обрабатываем готовую строку при получении "\п". При этом отпадает необходимость в синхронном вызове <FILEHANDLE>. Другое решение (без проверки файлов) описано в рецепте 7.15. Модуль IO::Select скрывает от вас операции с битовыми векторами. Метод 10: :Select->new() возвращает новый объект, для которого можно вызвать метод add, чтобы дополнить набор новыми файловыми манипуляторами. После включениях всех интересующих вас манипуляторов вызываются функции can read, can write и can exception. Функции возвращают список манипуляторов, ожидающих чтения, записи или непрочитанных срочных данных (например, информации о нарушении диапазона TCP). Вызовы 4-аргументной версии select не должны чередоваться с вызовами каких-либо функций буферизованного вывода, перечисленных во введении (read, о, seek, tell и т. д.). Вместо этого следует использовать sysread - вместе с sysseek, если вы хотите изменить позицию внутри файла для данного манипулятора. Чтение данных из сокета или канала с немедленным продолжением работы описано в рецепте 17.13. Асинхронному чтению с терминала посвящены рецепты 15.6 и 15.8. t> Смотри также- Описание функции select ъpeHfunc{\); документация но стандартному модулю IO::Select; рецепт 7.14. 7.14. Асинхронный ввод/вывод Проблема требуется прочитать или :аписать данные через файловый манипулятор так, чтобы система не приостанавливала процесс до наступления готовности программы, файла, сокета или устройства на другом конце. Такая задача чаще возникает для специальных, нежели для обычных файлов. Решение Откройте файл функцией sysopen с параметром 0 NOCBLOCK: use Fcntl; sysopen(MODEM, "/dev/cuaO", 0 NONBLOCK0 RDWR) or die "Cant open modem: $!\n"; Если у вас уже есть файловый манипулятор, измените флаги с помощью функции fcntl: use Fcntl; $flags = ; fcntKHANDLE, F GETFL, Sflags) or die "Couldnt get flags for HANDLE : $!\n"; $flags 1= 0 NONBLOCK; fcntKHANOLE, F SETFL, $flags) or die "Couldnt set flags for HANDLE: $!\n"; После того как файловый манипулятор будет открыт для асинхронного ввода/вывода, измените флаги с помощью функции fcntl: use POSIX qw(:errno h); $rv = syswrite(HANDLE, $buffer, length $buffer); if (!defined($rv) && $! == EAGAIN) { # Ожидание } elsif ($rv != length Sbuffer) { # Незавершенная запись } else { n Успешная запись $rv = sysread(HANDLE, Sbuffer, SBUFSIZ); or die "sysread: $!"; if (!defined($rv) 8.8, $! == EAGAIN) { # Ожидание } else { # Успешно прочитано $rv байт из HANDLE Комментарий Константа 0 NONBLOCK входит в стандарт POSIX и потому поддерживается больщинством компьютеров. Мы используем модуль POSIX для получения числового значения ошибки EAGAIN. t> Смотри также- Описание функций sysopen и fcntl вperlfunc{i); документация по стандартному модулю POSIX; страницы руководства ореп(2) и fcntl(2); рецепты 7.13 и 7.15. 7.15. Определение количества читаемых байтов Проблема Требуется узнать, сколько байтов может быть прочитано через файловый манипулятор функцией read или sys read. Решение Воспользуйтесь функцией ioctl в режиме FIONREAD: $size = packCL", 0); ioctKFH, $FI0NREAD, Ssize) or die "Couldnt call ioctl: S!\n"; 7.15. Определение количества читаемых байтов 271 Ssize = unpackCL", Ssize); # Могут быть прочитаны Ssize байт Комментарий Функция Perl ioctl предоставляет прямой интерфейс к системной функции ioctl(2). Если ваш компьютер не поддерживает запросы FIONREAD при вызове ioctl(2), вам не удастся использовать этот рецепт. FIONREAD и другие запросы ioctl(2) соответствуют числовым значениям, которые обычно хранятся в заголовочных файлах С. Вам может понадобиться утилита Perl h2ph, преобразующая заголовочные файлы С в код Perl. FIONREAD в конечном счете определяется как функция в файле sys/ioctl.ph: require sys/iootl,ph; Ssize = paokCL", 0); lOGtKFH, FIONREADO, Ssize) or die "Couldnt call ioctl: S!\n"; Ssize = unpackCL", Ssize); Если утилита h2ph не установлена или не подходит вам, найдите нужное место в заголовочном файле с помощью grep: %grep FIONREAD /usr/include/*/* /usr/include/asm/ioctls.h:#define FIONREAD 0x541B Также можно написать небольшую программу на С в «редакторе настоящего программиста»: % cat > fionread.c #include <sys/ioctl.h> main() { printf("%#08x\n", FIONREAD); "D % cc -0 fion read fion read % ./fionread 0x4004667f Затем жестко закодируйте полученное значение в программе. С переносимостью пускай возится ваш преемник: SFIONREAD = 0x4004667f; # XXX; зависит от операционной системы Ssize = pack("L", 0); ioctUFH, SFIONREAD, Ssize) or die "Couldnt call ioctl; S!\n"; Ssize = unpackCL", Ssize); FIONREAD требует, чтобы файловый манипулятор был подключен к потоку. Следовательно, сокеты, каналы и терминальные устройства будут работать, а файлы - нет. Если вам это покажется чем-то вроде системного программирования, взгляните на проблему под другим углом. Выполните асинхронное чтение данных из ма- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 [ 84 ] 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |