2008-10-08 6 views
4

J'ai un serveur TCP très simple écrit en C. Il s'exécute indéfiniment, en attente de connexions. Sous Windows, j'utiliser select pour vérifier l'activité sur la prise, et s'il n'y en a pas, je le code suivant pour me permettre d'arrêter de fumer en appuyant sur « q » sur le clavier:Comment puis-je capturer des frappes uniques dans une application console Unix sans bloquer?

if(kbhit()) { 
    char c = getch(); 
    if(c == 'q') break; 
} 

Ce doesn ne fonctionne pas sur unix, car kbhit n'existe pas et getch fonctionne différemment. J'ai trouvé sample code qui utilise tcsetattr pour modifier les paramètres du terminal et permettre l'entrée caractère par caractère. Après avoir appelé la fonction init, j'ouvre/dev/stdin (avec O_NONBLOCK) et lit un caractère, mais read(f, &c, 1) jusqu'à ce qu'un personnage soit frappé.

Je suppose que je pourrais générer un thread séparé et attendre attendre indéfiniment, puis signaler le premier thread si l'utilisateur frappe 'q', mais cela semble un peu lourd. Sûrement il y a un moyen plus facile?

Répondre

5

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.

+0

Même si mon application n'utilise pas déjà select, cela fonctionnera. Le fait que j'utilise déjà select le rend très facile, et ça fonctionne comme un charme. Merci –

1

plutôt ajouter "f" de votre

read(f, &c, 1) 

pour sélectionner appel. Lorsque f est prêt pour la lecture, un caractère a été enfoncé et read() ne bloquera pas.

1

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 la manière habituelle, ces jours-ci, d'accéder au terminal de contrôle d'un processus. Les manipulations de périphériques autres que open/close/read/write sont toutes gérées par l'appel système ioctl (2) pour 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 (qui peut ou non être stdin)

Modifier le mode de fonctionnement sur ce terminal pour revenir sans attendre une ligne complète d'entrée (qui est la valeur par défaut)

Continuez avec le reste de votre programme, sachant que les lectures de ce terminal (qui peut être stdin) peuvent renvoyer des lignes partielles ou même des caractères zéro sans qu'il s'agisse d'une erreur ou d'une condition de terminaison.


se trouve à la C-programming faq Une réponse détaillée sur la façon de faire la deuxième étape. Ils soulignent également que c'est une question de système d'exploitation, pas une question de langue. Ils offrent neuf possibilités, mais les trois principaux pertinents à cette question sont

  1. Utilisez les malédictions (3) Bibliothèque
  2. anciens systèmes de type BSD, utilisez sgttyb pour définir cbreak ou RAW
  3. Posix ou ancien système systèmes de style V, utilisez TCGETAW/TCSETAW pour définir c_cc [VMIN] à 1 et c_cc [VTIME] à 0.

Après quelques références dans le C FAQ pourrait conduire à la this page of kbhit code fragments.

Questions connexes