使用select()系统调用来监听stdin和服务器

时间:2011-03-19 06:53:27

标签: c linux select-function

我想使用select系统调用来复用STDIN和SOCKFD(连接到服务器),这样我必须同时监听STDIN和SOCKFD,并且根据数据的可读位置,我必须继续进行。

注意:#define STDIN 0

当我执行以下操作时会发生这种情况。

  • 我以通常的方式连接到服务器[socket()然后connect()]
  • 我将STDIN和连接套接字描述符'SOCKFD'添加到用于读取的fd_set(名为'readset')。
  • 然后我调用select()。
  • 使用FD_ISSET确定哪个fd已准备好进行读取。

这个设置的问题是FD_ISSET对于fd都是正确的。一旦我连接到服务器,我看到FD_ISSET(sockfd,& readset)始终为true,因此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 个答案:

答案 0 :(得分:4)

什么是STDIN?在<stdio.h>中声明了stdin,它是一个FILE *而不是文件描述符,因此不能在fdset和STDIN_FILENO中使用,它在<unistd.h>中定义并且是文件描述符,因此可以与fdsets一起使用。

BTW,在<stdio.h>中还有一个函数fileno(),它返回FILE *的文件描述符(根据你的编译标志,你可能需要定义一些特征宏来获取声明)