让netcat在断开连接后丢弃所有字节

9

我使用netcat通过bash运行一个小型开发web服务器,它只能处理一次连接。

启动netcat的命令如下(使用-k参数使其可以处理多个连接):

nc -kl 3000

一个Bash脚本会处理通过netcat接收到的浏览器请求,并构建响应,然后通过同一netcat实例将响应发送回浏览器。

一切都按预期进行,但有时浏览器无法获取其请求的文件。我怀疑:如果在响应完全发送之前关闭连接,则响应剩余部分将作为响应发送到下一个请求(当然不属于该请求)。

证明

  1. 终端1(服务器):nc -kl 3000
  2. 终端2(模拟浏览器):nc localhost 3000
  3. 在终端1中输入hello\n
  4. 终端2打印出hello\n
  5. 在终端2中按Ctrl+C以结束连接。
  6. 在终端1中输入world\n
  7. 再次在终端2中运行nc localhost 3000(新连接)。
  8. 尽管world\n实际上是在不存在连接时发送的,即作为第一个连接的第二个响应行,但终端2立即显示了world\n

所需行为:如果没有连接存在,则忽略传递给netcat的所有字节。

使用netcat是否可能实现?(我更喜欢像netcat这样的工具,因为它预装在所有计算机上。)


能详细说明一下您是如何在netcat和您的脚本之间进行交互吗? - zmo
我提出这个问题是因为我的编辑(在该行之后)。 - zmo
1
你需要让你的HTTP服务器程序生成你想要运行的脚本,这样在断开连接时,输出将会被丢弃,因为脚本会将执行权交还给父进程。我相信nmap的ncat可以做到这一点。或者你可以编写自己的Web服务器,在那里你将控制文件描述符,并能够确保在客户端断开连接时刷新所有输出。 - zmo
1
好的,Python 在 Ubuntu 上是默认安装的,并且提供了一个极简的 Web 服务器实现。例如,要服务于文件,您只需执行 python -m SimpleHTTPServer <port>(在 Python 3.x 中变成了 http.server),这相当容易进行自定义 - zmo
1
这是一个很好的观点,谢谢。我正在尝试使用ncat,如果它不起作用,我将使用Python的简单HTTP服务器。 - ideaboxer
显示剩余3条评论
2个回答

3

好的,如果您能够这样做,作为解决方法,而不是使用保持打开选项运行 ncat,只需在 while 循环中在每个连接之间重新生成它:

while true; do
    #what you want to do with: ncat -l 3000 
done

每次进程重新生成时,它将丢弃所有的标准输入,并从下一个I/O开始为接下来的进程重新启动。 当然,如果重新生成你的Bash脚本不方便,那可能意味着你没有使用正确的工具来完成工作。(你可以通过玩弄fifo或者使用临时文件描述符来解决这个问题,但这样做会过度设计以避免用更适合工作的语言编写一个脚本)。
如果您还没有这样做,您是否尝试从netcat运行脚本而不是反过来呢?
ncat -kl 3000 -c ./script.sh

它将为每个连接生成脚本,然后重定向stdin/stdout。当客户端断开连接时,脚本将被终止并应该释放您的输入fd。
实际上,如果您正在作为http服务器提供文件,则可能需要查找:
ncat -lk 3000 --lua-exec httpd.lua

使用与ncat发行版一起提供的httpd.lua来实现。


如果您想要一个简单的脚本在系统上运行某些操作,可以编写一个小型的Python脚本。它默认安装在Ubuntu(和许多其他系统)上,并且提供了一个极简的Web服务器实现,例如要提供文件服务,只需执行以下操作:
python -m SimpleHTTPServer <port>

它非常容易定制,以适应您独特的需求,并为您提供对套接字和文件描述符的完全控制。


如果我使用循环,而没有监听套接字,随着时间的推移,这将无法工作。如果我有错误,请纠正我。 - ideaboxer
你是什么意思? - zmo
1
实际上,即使重新生成之间的时间很短,它仍然会发生。但是,如果在这个“短”时间内有一丝连接的可能性,那么您可能认为您正在使用错误的工具来完成任务,并且可能表明您应该使用比shell更灵活的语言编写某些内容(例如Python、Ruby、Lua等)。您可以编写整个netcat+脚本,或者一个netcat替代品,它将删除标准输出,直到下一个连接。 - zmo
1
尽管在netcat的nmap版本中,如我所示,有一种方法可以生成一个进程,其stdin/stdout将是本地的,因此很有可能会响应您的请求。 - zmo
1
实际上,nmap已经接管了netcat的开发,我相信它应该是官方源代码树☺ - zmo
显示剩余5条评论

2

为了实现“随处运行”的脚本需求,您可以尝试逐行处理输入,并使用netstat检测是否存在已建立的连接:

while read line; do 
  netstat -an | grep 3000 | grep -q ESTABLISHED; 
  ret=$?; 
  if [ "$ret" == "0" ]; then 
    echo $line; 
  else 
    # this output is just for fun, and can be removed
    echo "not sending $line" >&2; 
  fi; 
done | nc -kl 3000

这种方法的限制在于它是基于行的,如果netstat调用后连接关闭,则可能会错误地向netcat发送数据。两个grep调用应确保您不会错误地检测到自己的grep。

我尝试查找netcat在连接关闭时返回的信号,但在shell中看不到任何暴露的信号。

可以使用fifo来演示netcat保持其stdin打开,即使不存在连接:

mkfifo test

nc -kl < test

# then in a different shell
for a in {0..5}; do echo hi > test; done

for不会阻塞,因此netcat正在主动读取stdin,但会缓冲它(我看不到关闭缓冲的选项)。这意味着您无法通过区分带有或不带有活动连接的netcat来真正区分它们,除非查看网络状态。 netstat是获取此状态的众多方法之一。


我喜欢你的解决方案,因为它在连接丢失后立即停止发送。不幸的是,它太慢了,因为我需要为每个字节测试连接,即使这样也不能保证100%可靠,因为在客户端关闭连接后发送的最后一个字节将通过下一个连接传输。 - ideaboxer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接