Comment capturer des frappes uniques dans une application de console Unix sans bloquer?
Question
J'ai un serveur TCP très simple écrit en C. Il fonctionne indéfiniment, dans l'attente des connexions. Sous Windows, j’utilise select
pour vérifier l’activité du socket. S’il n’en existe pas, j’ai le code suivant pour me permettre de quitter en appuyant sur la touche 'q' du clavier:
if( kbhit() ) {
char c = getch();
if( c == 'q' ) break;
}
Cela ne fonctionne pas sous unix, car kbhit
n'existe pas et getch
fonctionne différemment. J'ai trouvé un exemple de code qui utilise tcsetattr
pour modifier les paramètres du terminal et permettre la saisie caractère par caractère. Après avoir appelé la fonction init, j'ouvre / dev / stdin (avec O_NONBLOCK
) et lis un caractère, mais read (f, & amp; c, 1)
bloque jusqu'à ce qu'un caractère est touché.
Je suppose que je pourrais créer un thread distinct et le faire attendre , attendre indéfiniment, puis signaler le premier thread si l'utilisateur appuie sur "q", mais cela semble un peu lourd. Il y a sûrement un moyen plus facile?
La solution
Ajoutez stdin à votre liste de poignées de sélection et, s'il contient des données, appelez read pour en lire un caractère.
Autres conseils
Ajoutez plutôt "& f;" de votre
read( f, &c, 1 )
pour sélectionner un appel. Lorsque f est prêt à être lu, un caractère a été pressé et read () ne bloquera pas.
Sous Unix, que ce soit sur la console système ou dans une fenêtre de terminal X, les E / S du clavier passent par un terminal virtuel. Device / dev / tty est le moyen habituel, ces jours-ci, d'accéder au terminal de contrôle d'un processus. Les manipulations de périphérique autres qu'ouvrir / fermer / lire / écrire sont toutes gérées par l'appel système ioctl (2) de ce périphérique spécifique. L’idée générale de ce que vous voulez faire est
Ouvrez le terminal de contrôle (stdin ou non)
Changez le mode de fonctionnement sur ce terminal pour revenir sans attendre une ligne complète d'entrée (ce qui est la valeur par défaut normale)
Continuez avec le reste de votre programme, sachant que les lectures de ce terminal (qui peuvent être stdin) peuvent renvoyer des lignes partielles ou même zéro caractères sans que cela soit une erreur ou une condition de fin.
- Utiliser la bibliothèque curses (3)
- Anciens systèmes de style BSD, utilisez sgttyb pour définir CBREAK ou RAW
- Systèmes de style Posix ou anciens de type System V, utilisez TCGETAW / TCSETAW pour définir c_cc [VMIN] sur 1 et c_cc [VTIME] sur 0.
Après quelques références dans la FAQ C, cela pourrait conduire à cette page de fragments de code kbhit .