c/c++语言开发共享这个_popen / select示例有什么问题?

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

我现在知道我正在尝试在nonsocket上进行Socket操作。 或者我的fd_set无效,因为:

select返回-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: %dn",returncode); printf("Last Error: %dn",WSAGetLastError()); } else { if(FD_ISSET(_fileno(output),&fd)) { if(fgets(buff, sizeof(buff), output) != NULL ) { printf("Output: %sn", buff); } } else { printf("."); } } Sleep(500); } return 0; } 

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

    您有一些数据可供阅读,但您实际上并没有阅读任何内容。 下次轮询描述符时,数据仍然存在。 在继续轮询之前排空管道。

    据我所知,Windows匿名管道不能与像select这样的非阻塞调用一起使用。 因此,虽然您的_popen和select代码看起来很独立,但您无法将两者结合在一起。

    这是其他地方的类似post。

    使用PIPE_NOWAIT标志调用SetNamedPipeHandleState可能对你有用,但MSDN对这个主题有点神秘。

    所以,我认为你需要考虑实现这一目标的其他方法。 我建议在单独的线程中进行读取,并使用普通的阻塞I / O.

    首先,正如您和其他人所指出的那样, select()仅对Windows下的套接字有效。 select()不适用于_popen()返回的流。 错误10038明确指出了这一点。

    我不明白你的例子的目的是什么。 如果你只是想生成一个进程并收集它的stdout,那就这样做(直接来自MSDN _popen页面):

     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 %dn", _pclose( pPipe ) ); } else { printf( "Error: Failed to read the pipe to the end.n"); } } 

    而已。 无需选择。

    而且我不确定线程​​如何帮助你,这只会使你的问题复杂化。

    我注意到的第一件事是错误的是你在每个条件中的exceptfds上调用FD_ISSET。 我想你想要这样的东西:

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

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

    select的第一个参数需要是三个集合中任何一个中编号最大的文件描述符,加1:

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

    也:

      if(FD_ISSET(filePointer,&exceptfds)) { printf("i have datan"); } 

    应该:

      if(FD_ISSET(filePointer,&fd)) { printf("i have datan"); } 

    您应该从select()检查返回码。

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

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

    编辑:

    显然在Windows上,nfds被忽略,但应该正确设置,这样代码就更容易移植了。

    如果要使用超时,则需要将其作为最后一个参数传递给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. } } 

    因为select不起作用我使用了线程,特别是_beginthread_beginthreadex

      以上就是c/c++开发分享这个_popen / select示例有什么问题?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。

      本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

      ctvol管理联系方式QQ:251552304

      本文章地址:https://www.ctvol.com/c-cdevelopment/541921.html

      (0)
      上一篇 2021年1月5日
      下一篇 2021年1月5日

      精彩推荐