Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么在使用boost::asio for STDIN/STDOUT连接到程序时,EAGAIN的read()会失败?_C++_Linux_Boost_Boost Asio - Fatal编程技术网

C++ 为什么在使用boost::asio for STDIN/STDOUT连接到程序时,EAGAIN的read()会失败?

C++ 为什么在使用boost::asio for STDIN/STDOUT连接到程序时,EAGAIN的read()会失败?,c++,linux,boost,boost-asio,C++,Linux,Boost,Boost Asio,我有一个小程序,它与服务器建立SSL连接,然后将数据从STDIN复制到服务器,并将数据从服务器复制到STDOUT(很像openssl s_client)。我正在使用boost::asio来读写STDIN、STDOUT和SSL套接字。问题是,我无法从另一个程序(我的程序)导入数据 cat | myprog 我键入一行并按enter键,所有操作都正常:文本行通过我的程序找到它的路径,到达响应的服务器,响应被打印到我的控制台。下次我发送命令时,cat发送命令,但在下一次read()调用时失败(我键入

我有一个小程序,它与服务器建立SSL连接,然后将数据从STDIN复制到服务器,并将数据从服务器复制到STDOUT(很像
openssl s_client
)。我正在使用boost::asio来读写STDIN、STDOUT和SSL套接字。问题是,我无法从另一个程序(我的程序)导入数据

cat | myprog
我键入一行并按enter键,所有操作都正常:文本行通过我的程序找到它的路径,到达响应的服务器,响应被打印到我的控制台。下次我发送命令时,
cat
发送命令,但在下一次
read()
调用时失败(我键入以“echo”开头的行):

为什么会这样

strace
cat
确认这一点:

read(0, "echo foo\n", 32768)            = 9
write(1, "echo foo\n", 9)               = 9
read(0, "echo bar\n", 32768)            = 9
write(1, "echo bar\n", 9)               = 9
read(0, 0xa02c000, 32768)               = -1 EAGAIN (Resource temporarily unavailable)
理论#1:boost::asio正在将STDIN设置为非阻塞,但这也影响了
cat
的STDIN。如果我将代码从预处理器更改为
fork()
,允许它继承STDIN和STDERR,并捕获asio可以直接读取的STDOUT,那么这应该不会是一个问题。那样的话,我就不用去碰STDIN了。这已经完成,并且
strace
确认文件描述符0已被保留

理论2:当我的程序写入STDOUT时,它会将STDIN从阻塞变为非阻塞。我认为情况并非如此:

14211 read(0,  <unfinished ...>
//myprog (pid 14209) does epoll stuff here
//cat (pid 14211) receives my command
14211 <... read resumed> "echo foo\n", 32768) = 9
//more epoll
//cat writes
14211 write(1, "echo foo\n", 9)         = 9
14209 <... epoll_wait resumed> {{EPOLLIN, {u32=136519504, u64=136519504}}}, 128, -1) = 1
//cat starts reading again
14211 read(0,  <unfinished ...>
//my prog receives command from cat
14209 readv(3, [{"echo foo\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 512}], 1) = 9
//sends it to the server (encrypted)
14209 sendmsg(7, {msg_name(0)=NULL, msg_iov(1)=[{"\27\3\3\0'T\252\251\317w\255\310}h\322\222%\204\326FA\271\302\241\376\237\7\377\275\250o\262"..., 44}], msg_controllen=0, msg_flags=0}, MSG_NOSIGNAL) = 44
14209 epoll_wait(5, {{EPOLLIN|EPOLLOUT, {u32=136514856, u64=136514856}}}, 128, 0) = 1
14209 readv(3, 0xbfd8be04, 1)           = -1 EAGAIN (Resource temporarily unavailable)
//receives response
14209 recvmsg(7, {msg_name(0)=NULL, msg_iov(1)=[{"\27\3\3\0\"\357\351\3276a\233\356C\326z\317\252\344\27A\f\t|\f\307\275u\344\\\351 \320"..., 17408}], msg_controllen=0, msg_flags=0}, 0) = 39
//myprog sets non-blocking IO on STDOUT
14209 ioctl(1, FIONBIO, [1])            = 0
//writes out response
14209 writev(1, [{"foo\n", 4}], 1)      = 4
//myprog does more epoll stuff again
//cat receives seccond command, not that that this call started before myprog wrote anything or called ioctl()
14211 <... read resumed> "echo bar\n", 32768) = 9
14209 <... epoll_wait resumed> {{EPOLLOUT, {u32=136514720, u64=136514720}}}, 128, -1) = 1
14211 write(1, "echo bar\n", 9 <unfinished ...>
14209 epoll_wait(5,  <unfinished ...>
14211 <... write resumed> )             = 9
14209 <... epoll_wait resumed> {{EPOLLIN, {u32=136519504, u64=136519504}}}, 128, -1) = 1
14211 read(0,  <unfinished ...>
14209 readv(3,  <unfinished ...>
//cat's next read fails
14211 <... read resumed> 0x8d6f000, 32768) = -1 EAGAIN (Resource temporarily unavailable)
14211读取(0,
//myprog(pid 14209)在这里进行epoll操作
//cat(pid 14211)接收我的命令
14211“echo foo\n”,32768)=9
//多爱波尔
//猫写
14211写入(1,“echo foo\n”,9)=9
14209{{EPOLLIN,{u32=136519504,u64=136519504}},128,-1)=1
//猫又开始阅读了
14211读(0,
//我的程序从cat接收命令
14209 readv(3,[{“echo foo\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0”…,512}],1)=9
//将其发送到服务器(加密)
14209 sendmsg(7,{msg_name(0)=NULL,msg_iov(1)=[{{27\3\3\0'T\252\251\317w\255\310}h\322\222%\204\326FA\271\302\241\376\237\377\275\250o\262'..,44}],msg_controllen=0,msg_flags=0},msg_NOSIGNAL=44
14209 epoll_wait(5,{{EPOLLIN|epollut,{u32=136514856,u64=136514856}}},128,0)=1
14209 readv(3,0xbfd8be04,1)=-1 EAGAIN(资源暂时不可用)
//收到响应
14209 recvmsg(7,{msg_name(0)=NULL,msg_iov(1)=[{{27\3\3\0\”\357\351\3276a\233\356C\326z\317\252\344\27A\f\t|\f\307\275u\344\\\\\\ 351\320”“,msg_controllen=0,msg_flags=0},0)=39
//myprog在标准输出上设置非阻塞IO
14209 ioctl(1,FIONBIO,[1])=0
//写出响应
14209 writev(1,[{“foo\n”,4}],1)=4
//myprog又做了更多的epoll工作
//cat收到seccond命令,而不是在myprog编写任何东西或调用ioctl()之前启动此调用
14211“回音条\n”,32768)=9
14209{{epolout,{u32=136514720,u64=136514720}}},128,-1)=1
14211写入(1,“回音条\n”,9
14209 epoll_等待(5,
14211  )             = 9
14209{{EPOLLIN,{u32=136519504,u64=136519504}},128,-1)=1
14211读(0,
14209 readv(3,
//cat的下一次读取失败
14211 0x8d6f000,32768)=-1 EAGAIN(资源暂时不可用)

<>我的程序确实将它自己的STDUT更改为非阻塞,但是我可以看到它只剩下FD 0。它是可用的。

< P>大多数shell和终端工作的方式是STDIN和STDUT是同一文件的读/写文件描述符。
$ echo FOO >&0
FOO
祝贺您,您刚刚在stdin的文件描述符中写入了一些内容

文件的另一半可以在手册页中找到,在设置各种文件状态标志的
F_SETFL
fcntl()调用的描述旁边:

文件状态标志

每个打开的文件描述都有特定的关联状态标志, 由open(2)初始化,可能由fcntl()修改。 重复的文件描述符(由dup(2)、fcntl(F_DUPFD)制成), fork(2)等)引用相同的打开文件描述,因此 共享相同的文件状态标志

因此,你的理论#1基本上是正确的。如果你在头脑中计算出所有文件描述符是如何创建的,那么你的程序的标准输出和猫的标准输入最终会成为同一文件的不同描述符,这是因为shell设置每个启动程序的标准输入、输出和错误的方式;以及设置否使用文件描述符的n-blocking模式会影响同一底层文件句柄的所有描述符

请注意,上面引用的文档明确引用了
fork()
,因此您无法通过forking解决此问题,因为forking只是复制了相同的文件描述符

我有两个建议

  • 显式地
    打开(“/dev/tty”)
    以获得完全独立的文件句柄

  • 为什么您甚至需要将程序的标准输出设置为非阻塞模式?因为它进入终端,所以非阻塞模式并不能真正实现任何功能

  • $ echo FOO >&0
    FOO