卡在 stdin 读取直到 ^C 或 EOF,然后 "stdin spam"

Stuck on stdin reading until ^C or EOF, then "stdin spam"

向偶然发现我的 post 的任何有能力的人问好。
我需要前所未有的帮助。

我的问题是:

for(i = 1; i < 6; i++){
    wprintw(filsWin, "Entre ton choix en position %d :\n", i);
    wrefresh(filsWin);
                
    clean_stdin();
    choix = getchar();
                
    if(choix < '0' | choix > '7'){
        wprintw(filsWin, "Ce n'est pas dans les choix. Réessaie.\n");
        wrefresh(filsWin);
        i--;
    }
    else {
        combiGagnante[i-1] = choix;
        if(send(SockService, &choix, 1, 0) >= 0){
            wprintw(filsWin, "\n%s%cm%s%s inséré en position %d.\n\n", EXMNRM, combiGagnante[i-1], DOT, RSTCOL, i);
            wrefresh(filsWin);
        }
        else {
            perror("send()");
            raise(SIGINT);
        }
    }
}

我目前正在为我的学士学位制作 C 语言的 Mastermind,它必须是 2 个 TCP server-client 程序。 由于它的图形可能性,我想使用 ncurses 库,并且此代码是服务器的一部分,在客户端连接时由 child 进程执行。

问题在 choix = getchar();.

无论这里用什么来阅读stdin,我可以输入任何内容,终端甚至不会回应它。 ^C 在服务器上幸运地退出了它(感谢我的信号捕获 tbh)。 但是,如果我在连接期间在客户端上 ^C,客户端确实会像服务器一样终止(信号捕获 ftw),但是 getchar() 字面上 被淹没 无尽的 EOF (-1) 字符(这段代码用 if (choix < '0' | choix > '7') 语句响应),让我别无选择,只能最终 ^C 服务器。

我 运行 没有办法解决这个问题,因为我不知道什么可能会像那样发送垃圾邮件 stdin。我什至尝试冲洗并“清洁”它;徒劳无功(我需要摆脱 clean_stdin(),它什么都不做)。

我愿意接受任何解决方案,如果需要,我可以提供更多信息和代码。

提前致谢!

Stack Overflow 新手

P.S.: choixint,不是 char(为方便起见),filsWin 是 child的subwin

编辑: 作为对@Armali 的回应,这里是 server.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <uchar.h>

#include <arpa/inet.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>

#include <curses.h>

#include "mast_vars.h"

#define TRUE 1
#define FALSE 0

#define EXMNRM "\x1B[0;3"
#define RSTCOL "\x1B[0;0m"
//#define BLKCOL "\x1B[0;30m"
//#define REDCOL "\x1B[0;31m"
//#define GRNCOL "\x1B[0;32m"
//#define YLWCOL "\x1B[0;33m"
//#define BLUCOL "\x1B[0;34m"
//#define MAGCOL "\x1B[0;35m"
//#define CYACOL "\x1B[0;36m"
//#define WHTCOL "\x1B[0;37m"
#define DOT "\u2b24"
#define INVDOT "\u2022"


int SockEcoute, SockService;
WINDOW *pereWin, *filsWin;

int creerSocket(int, int *, struct sockaddr_in *);

void clean_stdin();

char convertPionIntoColor(char);

void segVSig(int sig);
void intSig(int sig);
void pipeSig(int sig);
void closeEverything();

int main(int argc, char *argv[]){
    struct sockaddr_in adresse;
    int portTCP, lg;
    
    char combiEssayees[5][essaisDonnes];
    char pionsInvest[5][essaisDonnes];
    
    int i, codGagne = 2, SockService = atoi(argv[1]);
    int32_t it;
    
    
    if(argc != 2 || argc == 1){
        fprintf(stderr, "Usage : MMSrvTCP <n°port>");
        exit(2);
    }

    signal(SIGINT, intSig);
    signal(SIGSEGV, segVSig);
    signal(SIGPIPE, pipeSig);
    
    portTCP=atoi(argv[1]);
    
    lg=sizeof(adresse);
    
    if((SockEcoute=creerSocket(SOCK_STREAM, &portTCP, &adresse))==-1){
        perror("Erreur creerSocket");
        exit(1);
    }
    
    if(listen(SockEcoute, 5)==-1){
        perror("Erreur listen");
        exit(2);
    }
    
    initscr();
    refresh();
    pereWin = subwin(stdscr, LINES / 2, COLS, 0, 0);
    box(pereWin, 0, 0);
    wrefresh(pereWin);
    
    wprintw(pereWin, "Serveur de PID %d lancé\n", getpid());
    
    while(1){
        wprintw(pereWin, "En attente d'un client.\n\n");
        wrefresh(pereWin);
        
        SockService=accept(SockEcoute, &adresse, &lg);
        wprintw(pereWin, "Connexion acceptée par %s\n", inet_ntoa(adresse.sin_addr));
        wrefresh(pereWin);
        
        if(fork() == 0){
            close(SockEcoute);
            dup2(SockService, STDIN_FILENO);
            close(SockService);
            
            filsWin = subwin(stdscr, LINES / 2, COLS, LINES / 2, 0);
            box(filsWin, 0, 0);
            wrefresh(filsWin);
            
            wprintw(filsWin, "Le choix de couleurs se fait ainsi :\n\n");
            wprintw(filsWin, "0 = Noir\n1 = Rouge\n2 = Vert\n3 = Jaune\n4 = Bleu\n5 = Magenta\n6 = Cyan\n7 = Blanc\n\n");
            wrefresh(filsWin);
            
            for(i = 1; i < 6; i++){
                wprintw(filsWin, "Entre ton choix en position %d :\n", i);
                wrefresh(filsWin);
                
                choix = getch();
                
                if(choix < '0' | choix > '7'){
                    wprintw(filsWin, "Ce n'est pas dans les choix. Réessaie.\n");
                    wrefresh(filsWin);
                    i--;
                }
                else {
                    combiGagnante[i-1] = choix;
                    if(send(SockService, &choix, 1, 0) >= 0){
                        wprintw(filsWin, "\n%s%cm%s%s inséré en position %d.\n\n", EXMNRM, combiGagnante[i-1], DOT, RSTCOL, i);
                        wrefresh(filsWin);
                    }
                    else {
                        perror("send()");
                        raise(SIGINT);
                    }
                }
            }
            
            do {
                wprintw(filsWin, "Combien veux-tu donner d'essais à ton décodeur ? 12 maxi.\n> ");
                wrefresh(filsWin);
                scanf("%d", &essaisDonnes);
                if(essaisDonnes > 12){
                    wprintw(filsWin, "C'est trop. Réessaie.\n");
                    wrefresh(filsWin);
                    //continue;
                }
                else if(essaisDonnes < 1){
                    wprintw(filsWin, "Bien tenté, mais tu ne peux pas ne pas lui donner d'essais. Réessaie.\n\n");
                    wrefresh(filsWin);
                    //continue;
                }
            } while(essaisDonnes >= 1 | essaisDonnes <= 12);
            
            it = htonl(essaisDonnes);
            if(send(SockService, &it, sizeof(it), 0) < 0){
                perror("recv() ");
                raise(SIGINT);
            }
            
            wprintw(filsWin, "Le décodeur se prépare...\n");
            wrefresh(filsWin);
            if(recv(SockService, &pret, 1, 0) < 0){
                perror("recv() ");
                raise(SIGINT);
            }
            
            if(pret == 'y' | pret == 'Y'){
                wprintw(filsWin, "Le décodeur est prêt, c'est parti.\n");
                wrefresh(filsWin);
                wgetch(filsWin);
            }
            else if(pret == 'n' | pret == 'N' | pret == 0x01){ // TODO : trouver le code FIN
                wprintw(filsWin, "Ah non, il est parti.\n\n");
                wrefresh(filsWin);
                close(SockService);
                wgetch(filsWin);
                wrefresh(filsWin);
                delwin(filsWin);
                clear();
                endwin();
                exit(1);
            }
            
            essaiActuel = 1;
            
            wclear(filsWin);
            
            while(essaiActuel <= essaisDonnes){
                wprintw(filsWin, "Essai N.%d en cours...\n\n", essaiActuel);
                wrefresh(filsWin);
                
                for(i = 0; i < 5; i++){
                    if(recv(SockService, &combiEssayees[i][essaiActuel-1], 1, 0) < 0){
                        perror("recv() ");
                        raise(SIGINT);
                    }
                    if(combiEssayees[i][essaiActuel-1] == 0x01){ // TODO : trouver le code FIN
                        wprintw(filsWin, "Le client nous a quitté.");
                        wrefresh(filsWin);
                        close(SockService);
                        wgetch(filsWin);
                        wrefresh(filsWin);
                        delwin(filsWin);
                        clear();
                        endwin();
                        exit(1);
                    }
                    
                    wprintw(filsWin, "%s%cm%s%s ", EXMNRM, combiEssayees[i][essaiActuel-1], DOT, RSTCOL);
                    //printw("%d octets reçus\n", nb);
                    wrefresh(filsWin);
                }
                
                wprintw(filsWin, "\n\nLe placement des pions d'investigation se fait ainsi :\n");
                wprintw(filsWin, "0 = Rien (mauvaise couleur, mauvais endroit)\n1 = Blanc (bonne couleur, mauvais endroit)\n2 = Noir (bonne couleur, bon endroit)\n\n");
                wprintw(filsWin, "C'est toi qui les place. Tu n'es pas obligé de les placer selon les positions.\n");
                wrefresh(filsWin);
                
                for(i = 0; i < 5; i++){
                    choix = wgetch(filsWin);
                    if(choix >= '0' | choix <= '2'){
                        pionsInvest[i][essaiActuel-1] = choix;
                        if(send(SockService, &choix, 1, 0) < 0){
                            perror("send()");
                            raise(SIGINT);
                        }
                        else {
                            wprintw(filsWin, "%s%cm%s%s ", EXMNRM, convertPionIntoColor(pionsInvest[i][essaiActuel-1]), INVDOT, RSTCOL);
                            wrefresh(filsWin);
                            
                            if(pionsInvest[i][essaiActuel-1] == '2') cpt++;
                        }
                    }
                    else {
                        wprintw(filsWin, "Ce n'est pas dans les choix. Réessaie.");
                        wrefresh(filsWin);
                        i--;
                    }
                }
                
                if(cpt == 5) {
                    codGagne = FALSE;
                    break;
                }
                else {
                    essaiActuel++;
                    if(essaiActuel > essaisDonnes) {
                        codGagne = TRUE;
                        break;
                    }
                    wprintw(filsWin, "Il a pas encore trouvé.");
                    wrefresh(filsWin);
                    wgetch(filsWin);
                }
            }
            
            switch(codGagne){
                case TRUE:
                    wprintw(filsWin, "C'est gagné ! Il a utilisé tous ses essais.");
                    wrefresh(filsWin);
                    break;
                case FALSE:
                    wprintw(filsWin, "Il a réussi en %d essais, dommage.", essaiActuel);
                    wrefresh(filsWin);
                    break;
                default:
                    wprintw(filsWin, "Ah ben le client est parti.\n");
                    wrefresh(filsWin);
                    break;
            }
            
            wprintw(filsWin, "Appuie sur n'importe quelle touche pour quitter.\n");
            wrefresh(filsWin);
            wgetch(filsWin);
            wrefresh(filsWin);
            delwin(filsWin);
            clear();
            endwin();
            exit(0);
        }
        
        wait(NULL);
        printf("oui");
        close(SockService);     
    }
}

int creerSocket(int type, int *portTCP, struct sockaddr_in *ptr_adresse){
    int desc;
    int longueur = sizeof(struct sockaddr_in);
    
    desc = socket(AF_INET, type, 0);
    if(desc==-1){
        perror("Erreur création de socket");
        return(-1);
    }
    
    ptr_adresse->sin_family = AF_INET;
    ptr_adresse->sin_port = htons(*portTCP);
    ptr_adresse->sin_addr.s_addr = INADDR_ANY;
    if((bind(desc, (struct sockaddr *)ptr_adresse, longueur))==-1){
        perror("Erreur bind");
        close(desc);
        exit(-1);
    }
    
    if(ptr_adresse != NULL)
        getsockname(desc, ptr_adresse, &longueur);
    
    return desc;
}



char convertPionIntoColor(char p){
    switch(p){
        case '0':
            return '[=12=]';
        case '1':
            return '7';
        case '2':
            return '0';
        default:
            return -1;
    }
}


void segVSig(int sig){
    printf("Erreur de segmentation.\n");
    closeEverything();
}

void intSig(int sig){
    printf("Commande d'interruption reçue.\n");
    closeEverything();
}

void pipeSig(int sig){
    printf("\nSIGPIPE reçu : communication interrompue.\n");
    closeEverything();
}

void closeEverything(){
    printf("Fermeture forcée du serveur.\n\n");
    close(SockService);
    close(SockEcoute);
    delwin(filsWin);
    refresh();
    delwin(pereWin);
    refresh();
    clear();
    endwin();
    exit(1);
}

如果需要,我也可以post客户。

编辑 2: mast_vars.h :

#ifndef _MAST_VARS_H
#define _MAST_VARS_H 1

int essaisDonnes, essaiActuel, choix;
int cpt = 0;

char pret;
char combiGagnante[5];

#endif

编辑 3: 没有了essaisDonnes = 0;,我把getchar()改成了getch()

我自己想出来的:

dup2() 在 STDIN_FILENO 中创建连接文件描述符的副本,仅在 close() 之后在标准输入中打开它,因此使用 [=12] 读取标准输入=]、getchar 或任何其他函数基本上是在等待客户端发送某些内容

删除两者都解决了我的问题:getch() 现在可以正常工作了。