Netcat双向通信

3
我正在尝试实现的目标是使客户端向服务器发送以下命令:
echo "Hello" | nc IP Port

收到“Hello”关键词后,服务器通过以下方式进行监听:
nc -nlp port

应该将" Hola "的响应发送回客户端。我尝试了以下操作,但在我的情况下都不起作用: 所以我目前面临的问题是,在从客户端收到“ Hello”后,服务器端无法将“ Hola”响应发送回客户端。有没有一种方法可以使用netcat做到这一点?如果可以,请指出我缺少了什么。
非常感谢您的帮助!
1个回答

4
您需要一些技巧和一些FIFO才能实现,但这完全是可行的:
#!/bin/bash

# Communication diagram:
# 
# +----------+          +------------+
# |          |  stdout  |            |   
# |    nc    | =======> | _feed_fifo |
# |          |          |            |
# +---stdin--+          +------------+
#      /\                ||
#      ||                || $fifo_ref 
#      ||                \/
#  +--stdout----------stdin-+
#  |                        |
#  |   __handle_fifo_data   |
#  |                        |
#  +------------------------+

fifo_ref="$RANDOM.fifo"
running_lock="$RANDOM.run"

# Strip leading and trailing white space (new line inclusive).
trim() {
    [[ "$1" =~ [^[:space:]](.*[^[:space:]])? ]]
    printf "%s" "$BASH_REMATCH"
}

# Handles data coming from the nc, with it's stdout connected
# directly to the client.
__handle_fifo_data() {
    # Keep trying to read the fifo while it exists
    while test -e "$1"
    do
        while read -r line
        do
            # This is where the magic happens. Anything sent to stdout will
            # be transmitted to the client connected to the nc
            echo "handling $line" >&2 # this is how we debug what's coming

            # Lines will include a \r in the end if coming from telnet.
            # Stripping the line from unwanted characters in the beginning/end
            # (line breaks, spaces, etc).
            message="$(trim "$line")"
            
            # Responding only if the message is "Hello"
            [ "$message" == "Hello" ] && {
                echo "Hola!"
            }
        done < $1 # feeding the loop with our fifo
    done
}

# Will read input and feed the fifo so we can handle data
__feed_fifo() {
    # This is important, otherwise we'll trash the terminal with lots of 
    # bash pids trying to read a dead stdin
    while test -e "$1"
    do
        # Testing again in case of concurrency
        test -e "$1" && cat - > "$1"
    done
}

# Cleaning up if something goes south or the program simply ends
trap "rm -rf ${fifo_ref} ${running_lock}" EXIT INT TERM HUP

# Let's get this party started
touch "$running_lock"

# Won't stop until you say so
while test -e "$running_lock"
do
    # Let's clear out the fifo so we don't get dirt from previous connections
    test -e "${fifo_ref}" && rm -rf "${fifo_ref}"
    mkfifo "${fifo_ref}"

    # Netcat port 9999
    # We'll feed the nc using our __handle_fifo_data and read from it to a
    # __feed_fifo which will try to keep stdin open all the time, feeding
    # __handle_fifo_data
    nc -l 9999 \
        0< <(__handle_fifo_data "${fifo_ref}") \
        1> >(__feed_fifo "${fifo_ref}")
done

你可以将它保存到类似 server.sh 的文件中,并在一个会话中运行以进行测试:
$ bash -x ./server.sh
handling Hello

在另一个会话中:

$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello
Hola!
^]
telnet> Connection closed.

为停止它,请键入^C

1
如果我想发送命令“quit”而不是“Hello”,然后连接将关闭,该怎么办?顺便说一下,这是一个很好的答案。恭喜! - robe007
1
好的,我得到了我需要的东西。只需添加这一行 => pkill -x nc > /dev/null 2>&1 并进行一些调整。您可以在此gist上看到一个示例。 - robe007
很棒的解决方案!请记住,pkill 命令也可能会杀死您同时运行的其他 netcat 实例,包括您的 server.sh - Gustavo Kawamoto

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