C 这个例子有什么问题?

C 这个例子有什么问题?,c,select,popen,C,Select,Popen,更新:我更新了代码和问题描述,以反映我的更改 我现在知道我正在非套接字上尝试套接字操作。或者我的fd_集合无效,因为: 选择返回-1和 WSAGetLastError()返回10038 但我似乎不知道那是什么。平台是Windows。我没有发布WSAStartup部分 int loop = 0; FILE *output int main() { fd_set fd; output = _popen("tail -f test.txt","r"); while(forc

更新:我更新了代码和问题描述,以反映我的更改

我现在知道我正在非套接字上尝试套接字操作。或者我的fd_集合无效,因为:

选择
返回-1和
WSAGetLastError()
返回10038

但我似乎不知道那是什么。平台是Windows。我没有发布
WSAStartup
部分

int loop = 0;
FILE *output

int main()
{
    fd_set fd;
    output = _popen("tail -f test.txt","r");

    while(forceExit == 0)
    {   
        FD_ZERO(&fd);
        FD_SET(_fileno(output),&fd);

        int returncode = select(_fileno(output)+1,&fd,NULL,NULL,NULL);
        if(returncode == 0)
        {
            printf("timed out");
        }
        else if (returncode < 0)
        {
            printf("returncode: %d\n",returncode);
            printf("Last Error: %d\n",WSAGetLastError());
        }
        else
        {
            if(FD_ISSET(_fileno(output),&fd))
            {
                if(fgets(buff, sizeof(buff), output) != NULL )
                {               
                    printf("Output: %s\n", buff);
                }
            }
            else
            {
                printf(".");
            }
        }
        Sleep(500);
    }
    return 0;
}
int循环=0;
文件*输出
int main()
{
fd_集fd;
输出=_popen(“tail-f test.txt”,“r”);
while(forceExit==0)
{   
FD_零(&FD);
FD_集(_文件号(输出),&FD);
int returncode=select(_fileno(output)+1,&fd,NULL,NULL,NULL);
如果(返回代码==0)
{
printf(“超时”);
}
否则如果(返回代码<0)
{
printf(“返回代码:%d\n”,返回代码);
printf(“上次错误:%d\n”,WSAGetLastError());
}
其他的
{
if(FD_ISSET(_fileno(输出),&FD))
{
if(fgets(buff,sizeof(buff),output)!=NULL)
{               
printf(“输出:%s\n”,buff);
}
}
其他的
{
printf(“.”);
}
}
睡眠(500);
}
返回0;
}

现在的新结果当然是打印出返回代码和最后一个错误。

要选择的第一个参数需要是三组中编号最高的文件描述符,加上1:

   int select(int nfds, fd_set *readfds, fd_set *writefds,
              fd_set *exceptfds, struct timeval *timeout);
此外:

应该是:

    if(FD_ISSET(filePointer,&fd))
    {
            printf("i have data\n");
    }
您应该检查select()中的返回代码

每次调用select()时,还需要重置fdsets

您不需要超时,因为您没有使用它

编辑:

显然,在Windows上,NFD被忽略,但可能应该正确设置,这样代码才更便于移植

如果要使用超时,需要将其作为最后一个参数传递到select调用中:

// Reset fd, exceptfds, and timeout before each select()...
int result = select(maxFDPlusOne, &fd, NULL, &exceptfds, &timeout);

if (result == 0)
{
    // timeout
}
else if (result < 0)
{
    // error
}
else
{
    // something happened
    if (FD_ISSET(filePointer,&fd))
    {
        // Need to read the data, otherwise you'll get notified each time.
    }
}
//在每次选择之前重置fd、ExceptFD和超时()。。。
int result=select(maxFDPlusOne,&fd,NULL,&exceptfds,&timeout);
如果(结果==0)
{
//超时
}
否则如果(结果<0)
{
//错误
}
其他的
{
//出事了
if(FD_ISSET(filePointer和FD))
{
//需要读取数据,否则每次都会收到通知。
}
}

我注意到的第一件事是错误的,即在每个条件中调用FD_ISSET对您的ExceptFD进行设置。我想你想要这样的东西:

if (FD_ISSET(filePointer,&fd))
{
    printf("i have data\n");
}
else ....

select中的except字段通常用于报告套接字上的错误或带外数据。当设置了异常的一个描述符时,它并不一定意味着错误,而是意味着某种“消息”(即带外数据)。我怀疑,对于您的应用程序,您可能不需要将文件描述符放入异常集中就可以通过。如果确实要检查错误,则需要检查select的返回值,如果它返回-1(或Windows上的SOCKET_ERROR),则需要执行某些操作。我不确定您的平台,因此我无法更具体地说明返回代码。

您已经准备好读取一些数据,但实际上没有读取任何内容。下次轮询描述符时,数据仍将存在。继续轮询之前,请排空管道

  • select()
    第一个参数是集合中文件描述符的最大值,加上1。(即输出+1)

    选择(输出+1,&fd,NULL,&EXPEPTFDS,NULL)

  • 第一个
    FD\u集(…)
    应该在
    FD\u集上

    if(FD_ISSET(filePointer和FD))

  • 您的数据流有数据,然后您需要读取该数据流。使用fgets(…)或类似工具从数据源读取数据

    char-buf[1024]; ... fgets(buf,sizeof(buf)*sizeof(char),输出)


  • 据我所知,Windows匿名管道不能用于select之类的非阻塞调用。因此,尽管您的_popen和select代码独立地看起来不错,但您不能将两者结合在一起

    使用PIPE_NOWAIT标志调用可能对您有用,但是MSDN在这个问题上有点神秘


    因此,我认为你需要寻找其他方法来实现这一点。我建议将读数放在一个单独的线程中,并使用普通的阻塞I/O。

    因为
    select
    不起作用,我特别使用线程。

    首先,正如您和其他人指出的那样,
    select()
    仅对Windows下的套接字有效
    select()
    不适用于
    \u popen()
    返回的流。错误10038清楚地标识了这一点

    我不明白你这个例子的目的是什么。如果您只是想生成一个进程并收集它的标准输出,只需执行以下操作(直接来自MSDN\u popen页面):

    就这样。无需选择


    我不确定线程在这里会如何帮助您,这只会使您的问题更加复杂。

    您关于需要正确设置的第一个参数的评论对于Berkeley sockets是正确的。在Windows中不是这样的。该参数未使用(尽管仍应正确设置!)。Poster没有指定平台,所以我想我应该指出平台中的不同。平台确实是Windows。很抱歉没有发布反映您的建议的更改,请选择-1。好的。。我试过你的方法,但没有用。你知道我怎样才能实现一个无阻塞的fgets吗?你不能,AFAICT。您最好的选择是简单地使用另一个线程进行读取,并执行正常的阻塞IO。
    if (FD_ISSET(filePointer,&fd))
    {
        printf("i have data\n");
    }
    else ....
    
    int main( void )
    {
    
       char   psBuffer[128];
       FILE   *pPipe;
    
       if( (pPipe = _popen("tail -f test.txt", "rt" )) == NULL )
          exit( 1 );
    
       /* Read pipe until end of file, or an error occurs. */
    
       while(fgets(psBuffer, 128, pPipe))
       {
          printf(psBuffer);
       }
    
    
       /* Close pipe and print return value of pPipe. */
       if (feof( pPipe))
       {
         printf( "\nProcess returned %d\n", _pclose( pPipe ) );
       }
       else
       {
         printf( "Error: Failed to read the pipe to the end.\n");
       }
    }