看完文章https://www.xmodulo.com/tcp-udp-socket-bash-shell.html,我试着写了一个简单的脚本:
#!/bin/bash
exec 3<>/dev/tcp/time.nist.gov/13
for i in {1..3}; do
echo -e "GET / HTTP/1.1\r\nhost: service\r\nConnection: close\r\n\r\n" >&3
cat <&3
echo "get sent"
sleep 10
done
exec 3<&-
echo "done"
它成功地返回了我的时间,但只有“错误的文件描述符”。
但是如果我移动文件描述符 3 的打开和打开,它运行良好
#!/bin/bash
for i in {1..3}; do
exec 3<>/dev/tcp/time.nist.gov/13
echo -e "GET / HTTP/1.1\r\nhost: service\r\nConnection: close\r\n\r\n" >&3
cat <&3
echo "get sent"
exec 3<&-
sleep 10
done
echo "done"
为什么会这样?
(我更愿意保持 TCP 套接字打开而不关闭并重新打开它。)
13端口是daytime协议,不是HTTP。因此,首先向服务器发送 HTTP 请求是错误的。相反,必须遵循白天协议的规范 - 请参阅维基百科:白天协议以获得概述。
基本上,该协议通过连接到服务器并读取直到连接关闭来工作——客户端根本不发送任何应用程序数据。由于必须阅读直到连接关闭并且没有“请求”的概念,因此也无法保持连接打开以获取更多“请求”。相反,必须为每个新查询创建一个新连接。
for i in {1..3}; do
exec 3<>/dev/tcp/time.nist.gov/13
cat <&3
exec 3<&-
sleep 10
done
echo "done"
但即使对方是 HTTP 服务器,尝试过的方法也行不通。其一:HTTP 请求明确要求
Connection: close
,因此排除了同一连接上的多个请求。并且,cat <&3
一直读取到服务器关闭连接而不是 HTTP 响应结束,这使得在同一连接上获得多个响应,因此也无法进行多个请求。