更新:我更新了代码和问题描述以反映我的更改。
我现在知道我正在尝试在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