linux – 为什么挂起SSH命令等待管道的输出,两端都在服务器的’sshd’中打开?

linux – 为什么挂起SSH命令等待管道的输出,两端都在服务器的’sshd’中打开?,第1张

概述这是在StackOverflow而不是SuperUser / ServerFault,因为它与sshd执行的系统调用和 *** 作系统交互有关,而不是我使用SSH的问题(虽然也赞赏它的帮助:p). 语境: 我通过SSH调用一系列复杂的脚本,例如ssh user @ host – / my / command.远程命令执行大量复杂的分支和执行,最终导致在远程主机上运行的后台守护程序进程.偶尔(我慢慢地试图找 这是在StackOverflow而不是SuperUser / ServerFault,因为它与sshd执行的系统调用和 *** 作系统交互有关,而不是我使用SSH的问题(虽然也赞赏它的帮助:p).

语境:

我通过SSH调用一系列复杂的脚本,例如ssh user @ host – / my / command.远程命令执行大量复杂的分支和执行,最终导致在远程主机上运行的后台守护程序进程.偶尔(我慢慢地试图找出可靠的再现条件),ssh命令永远不会将控制权返回给客户端shell.在这些情况下,我可以进入目标主机并看到sshd:user @ notty进程,没有子项无限期挂起.

解决这个问题不是这个问题的关键.这个问题是关于sshd进程正在做什么的.

SSH实现是OpenSSH,版本版本是5.3p1-112.el6_7.

问题:

如果我发现其中一个卡住了sshds并将其划掉,我可以看到它在两个手柄上进行选择,例如select(12,[3 6],[],NulL,NulL或类似.lsof告诉我其中一个句柄是连接回SSH客户端的TCP套接字.另一个是管道,另一端是仅在相同的sshd进程中打开.如果我使用this SuperUser question的答案通过ID搜索该管道,则包含对该管道的引用的唯一进程是相同的进程.lsof确认这一点:管道的读取和写入两端都是打开的在同一过程中,例如(对于管道788422703和sshd PID 22744):

sshd    22744 user    6r  FIFO                0,8      0t0 788422703 pipesshd    22744 user    7w  FIFO                0,8      0t0 788422703 pipe

问题:

什么是SSH等待?如果管道没有连接任何东西并且没有子进程,我无法想象它可能会发生什么事件.

什么是“循环”管道/它代表什么?我唯一的理论是,如果STDIN没有提供给SSH客户端,目标主机sshd会打开一个虚拟STDIN管道,因此它的一些内部子管理代码可以更加统一吗?但这看起来很脆弱.

SSH是如何进入这种情况的?

我尝试过的/附加信息:

>最初,我认为这是对守护进程的句柄泄漏.通过发出一个背景本身的命令,例如,可以创建一个等待的,无子项的sshd进程. ssh user @ host – ‘sleep 60&’; sshd将等待流被关闭到守护进程;不只是直接孩子的退出.由于有问题的脚本最终会在启动的守护进程中导致(在进程树中向下),因此守护进程最初可能会保留在句柄上.然而,这似乎并没有成功 – 使用睡眠60&以命令为例,与守护进程通信的sshd进程保持并选择四个打开的管道,而不仅仅是两个,并且至少有两个管道从sshd连接到守护进程,而不是循环.除非有一种跟踪/指向我不知道的管道的方法(并且可能存在 – 例如,我不知道欺骗文件句柄如何发挥close()信号量等待或管道),我不认为管道到自身的情况表示等待守护进程的情况.
> sshd定期接收TCP套接字/ ssh连接本身的通信,这会将其从选择中唤醒,进行短暂的通信(在此期间strace显示阻塞SIGCHLD),然后它返回等待相同的FD.
>我可能受到this race condition的影响(SIGCHLD在内核使管道中的数据可用之前交付).但是,这似乎不太可能,既考虑了这种情况的显示速度,又考虑了在目标主机上运行的进程是Perl脚本的事实,以及Perl runtime closes and flushes open file descriptors on shutdown.

解决方法 您似乎在描述通知管道. OpenSSH sshd主循环调用select()等待它有事可做.被轮询的文件描述符包括到客户端的TCP连接以及用于服务活动通道的任何描述符.

sshd希望能够在收到SIGCHLD信号时中断select()调用.为此,sshd为SIGCHLD安装信号处理程序,并创建一个管道.当收到SIGCHLD信号时,信号处理程序将一个字节写入管道.管道的读取结束包含在select()轮询的文件描述符列表中.写入管道的行为将导致select()调用返回,并指示通知管道是可读的.

所有代码都在serverloop.c中:

/* * we write to this pipe if a SIGCHLD is caught in order to avoID * the race between select() and child_terminated */static int notify_pipe[2];static voIDnotify_setup(voID){        if (pipe(notify_pipe) < 0) {                error("pipe(notify_pipe) Failed %s",strerror(errno));        } else if ((fcntl(notify_pipe[0],F_SETFD,1) == -1) ||            (fcntl(notify_pipe[1],1) == -1)) {                error("fcntl(notify_pipe,F_SETFD) Failed %s",strerror(errno));                close(notify_pipe[0]);                close(notify_pipe[1]);        } else {                set_nonblock(notify_pipe[0]);                set_nonblock(notify_pipe[1]);                return;        }        notify_pipe[0] = -1;    /* read end */        notify_pipe[1] = -1;    /* write end */}static voIDnotify_parent(voID){        if (notify_pipe[1] != -1)                write(notify_pipe[1],"",1);}[...]/*ARGSUSED*/static voIDsigchld_handler(int sig){        int save_errno = errno;        child_terminated = 1;#ifndef _UNICOS        mysignal(SIGCHLD,sigchld_handler);#endif        notify_parent();        errno = save_errno;}

设置和执行select调用的代码在另一个名为wait_until_can_do_something()的函数中.它相当长,所以我不会在这里包含它. OpenSSH是开源的,this page描述了如何下载源代码.

总结

以上是内存溢出为你收集整理的linux – 为什么挂起SSH命令等待管道的输出,两端都在服务器的’sshd’中打开?全部内容,希望文章能够帮你解决linux – 为什么挂起SSH命令等待管道的输出,两端都在服务器的’sshd’中打开?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/1018241.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存