Bash 中的 Socket 编程:/dev/tcp | Socket Programming in Bash
章节概述
核心理念:Bash 内置了 TCP/UDP 网络支持,通过
/dev/tcp/host/port特殊文件可以直接进行 socket 操作,无需额外工具。这类似于 C 语言的 socket API,但更加简洁。
第1节:/dev/tcp/host/port
1.1 基础连接
# 打开 TCP 连接
exec 3<>/dev/tcp/example.com/80
# 发送 HTTP 请求
echo -e "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n" >&3
# 读取响应
cat <&3
# 关闭连接
exec 3>&-1.2 语法详解
# /dev/tcp 是 Bash 内置的特殊文件
# 语法: /dev/tcp/host/port
# 打开连接
exec 3<>/dev/tcp/192.168.1.100/22
# 使用域名
exec 3<>/dev/tcp/example.com/443
# UDP 连接
exec 3<>/dev/udp/example.com/53第2节:文件描述符读写
2.1 文件描述符操作
# 分配文件描述符
exec 3<> /dev/tcp/host/port
# 读取数据
read -t 5 line <&3
# 写入数据
echo "data" >&3
# 关闭文件描述符
exec 3>&-
# 关闭输入端
exec 3<&-
# 关闭输出端
exec 3>&-2.2 多文件描述符
# 同时管理多个连接
exec 3<>/dev/tcp/server1/80
exec 4<>/dev/tcp/server2/80
echo "Request 1" >&3
echo "Request 2" >&4
read response1 <&3
read response2 <&4
exec 3>&- 4>&-第3节:TCP 服务器/客户端
3.1 简单 TCP 服务器
#!/bin/bash
# 简单 TCP 服务器
PORT=12345
echo "Starting server on port $PORT..."
while true; do
# 接受连接
exec 3<>/dev/tcp/0.0.0.0/$PORT
# 读取客户端数据
read -t 10 client_data <&3
echo "Received: $client_data"
# 发送响应
echo "Echo: $client_data" >&3
# 关闭连接
exec 3>&-
done3.2 并发 TCP 服务器
#!/bin/bash
# 并发 TCP 服务器
PORT=12345
MAX_CLIENTS=5
handle_client() {
local client_fd=$1
read -t 30 data <&$client_fd
echo "Client sent: $data"
echo "Response from server" >&$client_fd
exec $client_fd>&-
}
# 监听并处理连接
exec 4<>/dev/tcp/0.0.0.0/$PORT
while true; do
# 使用文件描述符 4 监听
# 接受新连接到文件描述符 5
exec 5<>/dev/tcp/0.0.0.0/$PORT
# 后台处理客户端
handle_client 5 &
# 限制并发数
while [ $(jobs -r | wc -l) -ge $MAX_CLIENTS ]; do
wait -n
done
done3.3 TCP 客户端
#!/bin/bash
# 简单 TCP 客户端
SERVER="example.com"
PORT=80
# 连接服务器
exec 3<>/dev/tcp/$SERVER/$PORT
# 发送数据
echo -e "GET / HTTP/1.1\r\nHost: $SERVER\r\n\r\n" >&3
# 读取响应
timeout 10 cat <&3
# 关闭连接
exec 3>&-第4节:UDP 支持
4.1 UDP 客户端
#!/bin/bash
# UDP 客户端
SERVER="8.8.8.8"
PORT=53
# 打开 UDP 连接
exec 3<>/dev/udp/$SERVER/$PORT
# 发送 DNS 查询(示例)
echo -ne '\x00\x01\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x07example\x03com\x00\x00\x01\x00\x01' >&3
# 读取响应
timeout 5 cat <&3 | xxd
# 关闭连接
exec 3>&-4.2 UDP 服务器
#!/bin/bash
# UDP 服务器
PORT=9999
while true; do
# 监听 UDP
exec 3<>/dev/udp/0.0.0.0/$PORT
# 读取数据
read -t 10 data <&3
echo "Received UDP: $data"
# 发送响应
echo "UDP Response" >&3
exec 3>&-
done第5节:超时设置
5.1 连接超时
# 使用 timeout 命令
timeout 5 bash -c 'echo "data" > /dev/tcp/example.com/80'
# 使用 select 进行超时检测
{
exec 3<>/dev/tcp/example.com/80
} 2>/dev/null
if [ $? -ne 0 ]; then
echo "Connection failed"
fi5.2 读取超时
# read 的 -t 选项
exec 3<>/dev/tcp/example.com/80
read -t 10 response <&3
if [ $? -gt 128 ]; then
echo "Read timed out"
fi
exec 3>&-5.3 写入超时
# 使用 timeout 限制写入时间
exec 3<>/dev/tcp/example.com/80
timeout 5 bash -c 'echo "data" >&3'
if [ $? -eq 124 ]; then
echo "Write timed out"
fi
exec 3>&-第6节:实际应用
6.1 HTTP 客户端
#!/bin/bash
# 使用 /dev/tcp 的 HTTP 客端
http_get() {
local host=$1
local path=${2:-/}
local port=80
exec 3<>/dev/tcp/$host/$port
echo -e "GET $path HTTP/1.1\r\nHost: $host\r\nConnection: close\r\n\r\n" >&3
while IFS= read -t 10 line; do
echo "$line"
done <&3
exec 3>&-
}
http_get example.com6.2 简单代理服务器
#!/bin/bash
# 简单 TCP 代理
LISTEN_PORT=8080
REMOTE_HOST="example.com"
REMOTE_PORT=80
exec 4<>/dev/tcp/0.0.0.0/$LISTEN_PORT
while true; do
exec 5<>/dev/tcp/$REMOTE_HOST/$REMOTE_PORT
# 双向数据转发
while true; do
read -t 5 data <&5 && echo "$data" >&5 &
read -t 5 data <&5 && echo "$data" >&4 &
done &
exec 5>&-
done6.3 网络测试工具
#!/bin/bash
# 测试端口连通性
test_port() {
local host=$1
local port=$2
local timeout=${3:-5}
timeout $timeout bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null
return $?
}
# 测试多个端口
for port in 22 80 443 3306 6379; do
if test_port "example.com" $port; then
echo "Port $port: OPEN"
else
echo "Port $port: CLOSED"
fi
done