Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с функциями tcsetattr, fcntl на C в Linux  (Прочитано 38248 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Bidanets
Интересующийся

ua
Offline Offline

« : 19-08-2015 08:27 » 

Здравствуйте, уважаемые форумчане!
Разбираюсь к кодом программы, написанной на C под Linux.
Попались функции tcsetattr и fcntl. Немного разобрался с их работой и предназначением сам, но очень смутно. Не могли бы вы объяснить для чего они предназначены и принцип их работы (а именно, как зависит их работа от аргументов).

Так же возник вопрос о том, что выполняет конструкция ниже? Что обозначает 0 - третий аргумент первой ф-ии?
Что обозначает выражение kbh_oldf | O_NONBLOCK?
С первыми двумя аргументами ф-ии fcntl разобрался, кажись. Первый - это файловый дескриптор, второй - команда, которую нужно выполнить: либо извлечь значения флагов(F_GETFL), либо записать новые значения (F_SETFL)

kbh_oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, kbh_oldf | O_NONBLOCK);

Так же интересует какую роль играет ф-ия tcgetattr(STDIN_FILENO, &kbh_oldt);

И последнее в этой теме:
Для чего используются структуры termios?
static struct termios kbh_oldt;
static struct termios kbh_newt;
static int kbh_oldf = 0;
kbh_newt.c_lflag &= ~(ICANON | ECHO); // Какое действие выполняет это выражение?
Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #1 : 19-08-2015 08:48 » 

Заранее спасибо всем, кто обратит внимание на этот пост!  Улыбаюсь
Записан
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #2 : 19-08-2015 08:53 » 

Разбираюсь к кодом программы, написанной на C под Linux.
Попались функции tcsetattr и fcntl. Немного разобрался с их работой и предназначением сам, но очень смутно. Не могли бы вы объяснить для чего они предназначены и принцип их работы (а именно, как зависит их работа от аргументов).

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

Так же возник вопрос о том, что выполняет конструкция ниже? Что обозначает 0 - третий аргумент первой ф-ии?
Что обозначает выражение kbh_oldf | O_NONBLOCK?
С первыми двумя аргументами ф-ии fcntl разобрался, кажись. Первый - это файловый дескриптор, второй - команда, которую нужно выполнить: либо извлечь значения флагов(F_GETFL), либо записать новые значения (F_SETFL)

kbh_oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, kbh_oldf | O_NONBLOCK);
мне кажется, что в первом вызове fcntl() часть ", 0" - лишняя, команда F_GETFL не требует дополнительного параметра.

а по сути, как я понимаю, для файлового дескриптора включается режим неблокированного ввода. Это, имхо, можно было сделать более явно, через ioctl():
Код: (C)
int flag = 1;
ioctl(STDIN_FILENO, FIONBIO, &flag);
Впрочем, подход через fcntl() считается более стандартным.


Так же интересует какую роль играет ф-ия tcgetattr(STDIN_FILENO, &kbh_oldt);
Функция tcgetattr() запрашивает текущие настройки терминала, а tcsetattr() из устанавливает.

И последнее в этой теме:
Для чего используются структуры termios?
static struct termios kbh_oldt;
static struct termios kbh_newt;
static int kbh_oldf = 0;
kbh_newt.c_lflag &= ~(ICANON | ECHO); // Какое действие выполняет это выражение?
В настройках терминала отключается канонический режим (редактирование командной строки и т.д.) и автоматический вывод вводимых символов на экран.
Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #3 : 19-08-2015 08:58 » 

ОГО! Не ожидал, что ответ будет так быстро и довольно исчерпывающим!
Большое вас спасибо!
Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #4 : 19-08-2015 09:02 » 

Большое вам* спасибо!
Записан
RXL
Технический
Администратор

Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 19-08-2015 11:25 » 

Bidanets, эти функции входят в стандартную библиотеку С. В поставке дистрибутива, помимо библиотек разработки, должен быть мануал. Я просматриваю его через pinfo libc - в другом дистрибутиве (у меня RedHat-образный) может быть иначе. Мне это дает более полное и быстрое понимание той или иной фичи.

Также следует знать, что в Unix/Linux много разновидностей файловых дескрипторов и они имеют различие в поведении. Это открытые файлы, сокеты, трубы (pipe), последовательные устройства, блочные устройства. На последовательные устройства может быть установлена дисциплина терминала. Например, STDIN может быть терминалом (/dev/pts/*, /dev/tty*), на который дисциплина терминала цепляется, а может быть файлом, на котором ее нет. Прежде чем настраивать терминал, нужно убедиться, что дескриптор является терминалом. Об этом посмотри в мануале.
« Последнее редактирование: 19-08-2015 11:34 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #6 : 21-08-2015 10:53 » new

Большое спасибо за подробное объяснение и помощь!
Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #7 : 21-08-2015 11:11 » 

Ниже есть ссылка на код программы на C под Linux. В продолжение этой темы хотел бы задать еще один вопрос.
В ф-ии main два раза вызывается ф-ия SetRawKbd, которая, включает и выключает канонический режим ввода с клавиатуры и включает и выключает эхо терминала, а так же изменяет переключает режимы "блокирующий/неблокирующий".
Вопрос такой:
1) Открываю wav-файл с пом. этой программы через терминал. Программа должна воспроизводить wav-файл с помощью PC-Speaker
2) Если не использовать ф-ию SetRawKbd, то PC-Speaker не будет воспроизводить аудио-файл.
Нужно понять почему он не работает, ведь SetRawKbd работает над связью клавиатуры и терминала, насколько я понял.
http://pastebin.com/8kMCyvUK
Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #8 : 21-08-2015 11:13 » 

Так же прикрепляю .h файл, который подключается к .C файлу.
http://pastebin.com/KEZJU4bE
Записан
darkelf
Молодой специалист

ua
Offline Offline

« Ответ #9 : 21-08-2015 12:13 » 

В ф-ии main два раза вызывается ф-ия SetRawKbd, которая, включает и выключает канонический режим ввода с клавиатуры и включает и выключает эхо терминала, а так же изменяет переключает режимы "блокирующий/неблокирующий".
Вопрос такой:
1) Открываю wav-файл с пом. этой программы через терминал. Программа должна воспроизводить wav-файл с помощью PC-Speaker
2) Если не использовать ф-ию SetRawKbd, то PC-Speaker не будет воспроизводить аудио-файл.
Нужно понять почему он не работает, ведь SetRawKbd работает над связью клавиатуры и терминала, насколько я понял.
http://pastebin.com/8kMCyvUK
Скорее всего это реализация неблокируемого getchar() в Вашем цикле по буферу wave-файла.

Код: (C)
                        for (i = 0; i < bufsize && ((kbh_ch = getchar()) == EOF); i += onechannelinc) {
На само воспроизведение оно никак не влияет, но если Вы убираете перевод stdin-а в неблокируемый режим, то при первом-же вызове getchar() программа блокируется на ожидании нажатия клавиатуры. Если Вы при этом нажмёте и будете удерживать клавишу ENTER, то, думаю, музыка вполне себе будет играть, хотя, возможно, и с определёнными искажениями, пока Вы не отпустите клавишу ENTER.

В unix-ах вообще и в linux в частности, не смотря на то, что функция называется getchar(), при включенном каноническом режиме драйвер терминала не отдаст программе введённый символ, пока не будет нажата клавиша ENTER. Это связано с тем, что в каноническом режиме есть редактирование строки и, быть может, Вы захотите удалить введённый символ и ввести другой.

Если Вы уберёте этот вызов getchar() и все вызовы SetRawKbd(), то всё будет работать, разве-что остановить программу можно будет по нажатию сочетания клавиш Ctrl+C, а не по любой клавише, как в текущей версии программы.

Мне кажется, что скорее всего этот код портировали из-под ms-dos, в котором была функция kbhit(), которая проверяла была-ли нажата клавиша или не блокируя при этом основную программу, в linux такой функции нет и соответственно, как я понимаю, автор выкрутился как мог.
« Последнее редактирование: 21-08-2015 12:26 от darkelf » Записан
Bidanets
Интересующийся

ua
Offline Offline

« Ответ #10 : 21-08-2015 18:30 » 

Спасибо большое за помощь! Вы очень помогли!  Улыбаюсь Да-да
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines