Использование системного вызова select () для прослушивания на stdin и на сервере - PullRequest
3 голосов
/ 19 марта 2011

Я хочу использовать системный вызов select для мультиплексирования STDIN и SOCKFD (подключенного к серверу), так что я должен прослушивать STDIN и SOCKFD, и в зависимости от того, где данные доступны для чтения, я должен продолжить.

Примечание: #define STDIN 0

Вот что происходит, когда я делаю следующее.

  • Я подключаюсь к серверу обычным способом [socket (), затем подключаюсь ()]
  • Я добавляю STDIN и дескриптор сокета соединения 'SOCKFD' к fd_set (названному 'readset'), предназначенному для чтения.
  • Затем я звоню select ().
  • Используйте FD_ISSET, чтобы определить, какой fd готов для чтения.

Проблема с этой настройкой заключается в том, что FD_ISSET всегда верно для обоих fd. Как только я подключаюсь к серверу, я вижу, что FD_ISSET (sockfd, & readset) всегда истинен, как и FD_ISSET (STDIN, & readset), независимо от того, отправляет ли сервер данные или нет, или я вводю данные с клавиатуры или нет.

Что я мог делать не так?

/ * соединение установлено * /

FD_ZERO(&connset);

while(1) {

    FD_SET(sockfd,&connset); /* add sockfd to connset */
    FD_SET(STDIN,&connset); /* add STDIN to connset */
    fdmax=sockfd;

    if(select(fdmax+1,&readset,NULL,NULL,NULL)<0){
        fprintf(stdout, "select() error\n");
        exit(0);
    }       

    /* select returned
    * check which socket is set
    */

    if(FD_ISSET(sockfd,&connset)) {

        /*
         * Server sends msglen 
         * client reads msg of length msglen
         * client prints it to stdout
         * client waits for next activity of its listen sockets
         */
        size=4;
        ptr=(char *)&msglen;
        while(1) {
            if((nread=recv(sockfd,ptr,size,0)),MSG_DONTWAIT) {
                close(sockfd);
                exit(0);
            }
            size-=nread;
            ptr+=nread;
        }
        bytesToRead = ntohl(msglen);
        readbuf = (char *)malloc(sizeof(char)*(bytesToRead+1));
        ptr=readbuf;
        while(1) {
            nread=recv(sockfd,ptr,bytesToRead,MSG_DONTWAIT);
            if(nread<=0) {
                close(sockfd);
                exit(0);
            }
            bytesToRead-=nread;
            ptr+=nread;
        }
        /* msg read successfully */
        *ptr='\0';
        fprintf(stdout, "in: %s\n",readbuf);
        free(readbuf);
    }

    if(FD_ISSET(STDIN,&connset)) {
        /* data at STDIN */
        fgets(buf,2,stdin); /* read the first newline char (< enter >) */
        fprintf(stdout,"Enter msg: ");
        fgets(buf,MAXLEN,stdin); /* read the msg */
        buf[strlen(buf)-1]='\0';
        msglen = htonl((uint32_t)(strlen(buf)-1));
        ptr = (char *)&msglen;
        bytesToSend = sizeof(uint32_t);
        cnt = bytesToSend;
        while(cnt>0) {
            if((nsent=send(sockfd,ptr,cnt,0))>0) {
                cnt-=nsent;
                ptr+=nsent;
            }
            else {
                fprintf(stdout,"send error\n");
                exit(0);
            }
        }
        ptr=buf;
        bytesToSend=(uint32_t)(strlen(buf)-1);
        cnt=bytesToSend;
        while(cnt>0) {
            if((nsent=send(sockfd,ptr,cnt,0))>0) {
                cnt-=nsent;
                ptr+=nsent;
            }
            else {
                fprintf(stdout,"send error\n");
                exit(0);
            }
        }       
    }       
}   
return 0;

}

1 Ответ

4 голосов
/ 19 марта 2011

Что такое STDIN?Существует stdin, который объявлен в <stdio.h>, это FILE *, а не дескриптор файла, поэтому его нельзя использовать в fdset и STDIN_FILENO, который определен в <unistd.h> и является дескриптором файла и, следовательно, может использоваться сfdsets.

Кстати, в <stdio.h> есть также функция fileno(), которая возвращает файловый дескриптор файла FILE * (в зависимости от ваших флагов компиляции, вам может потребоваться определить некоторые макросы функций, чтобы получить объявление).

...