Bash에서 소켓을 비동기적으로 열고 나중에 사용할 수 있나요?

Bash에서 소켓을 비동기적으로 열고 나중에 사용할 수 있나요?

Bash가 그렇게 많은 고급 기능을 지원할 것이라고는 예상하지 못했습니다! 나는 내가 찾은 것들을 시험해 보기 위해 간단한 웹 프로그램을 개발하기 시작했습니다. 내 특정 프로그램은 전적으로 Bash로 작성된 기본 Redis 클라이언트입니다. 현재 다음을 수행할 수 있습니다.

redis_command -c "ping" redis{001..100}:{6379..6400}

모든 인스턴스(약 2100)에 "ping" 명령을 보내고 결과를 반환합니다. 현재 "ping" 명령을 직렬로 보내고 있지만 초기 소켓 생성을 모두 병렬로 수행하면 프로그램 속도를 높일 수 있다고 생각했습니다. 최적화를 적용하거나 적용하지 않고 프로그램을 테스트한 결과 최적화로 인해 실제로 속도가 느려지는 것을 깨달았습니다. 최적화 효과는 다음과 같습니다.

declare -A SOCKETS
function get_socket {
  # args: <hostname> <port>
  # returns: the socket number, or failure return code

  # verify args
  if [[ -z "${1}" ]]; then
    return 1
  fi
  if [[ -z "${2}" ]]; then
    return 1
  fi

  local HOSTPORT="${1}:${2}"
  if [[ -z ${SOCKETS[${HOSTPORT}]} ]]; then
    exec {fd}<>/dev/tcp/${1}/${2}
    SOCKETS[${HOSTPORT}]=${fd}
    RES=${fd}
  else
    RES="${SOCKETS[${HOSTPORT}]}"
  fi
}

if [[ ${PRECONNECT} -eq 1 ]]; then
  echo -n "Pre-connecting to ${#HOSTS[@]} instances... " >&2
  for HOST in ${HOSTS[@]}; do
    get_socket "${HOST%%:*}" "${HOST##*:}" &
    PIDS+=($!)
  done

  # make sure all of our async connections finished before starting
  # TODO, check for errors
  for PID in ${PIDS[@]}; do
    wait ${PID}
  done
  echo "done" >&2
fi

일반적으로 get_socket() 함수는 그 자체로 잘 작동합니다. 특정 서버에 명령을 보내야 하는 경우 미리 get_socket()을 호출하고 실제로 명령을 보내고 응답을 구문 분석하는 다른 함수에 FD를 전달합니다. 사전 연결 시나리오에서는 &를 통해 백그라운드에서 get_socket을 호출합니다. get_socket()&은 별도의 프로세스에서 실행되므로 생성된 FD는 호출 프로세스에서 사용 가능/접근할 수 없으므로 최적화가 쓸모 없게 됩니다.

Bash에서 소켓을 통해 보낼 수 있는 방법이 있나요? 아니면 별도의 프로세스를 사용하지 않고 연결을 병렬화할 수 있는 다른 방법이 있나요?

답변1

직접 사용할 수 는 없지만 /dev/tcp/x/y파이프를 사용하여 백그라운드에서 시작된 프로세스와 통신하여 TCP 소켓을 연결하고 데이터를 전송할 수 있습니다.

그것은 마치

coproc hostA {
  exec {fd}<> /dev/tcp/127.0.0.1/80
  cat <&$fd & cat >&$fd
}

# same for hostB...

echo -e 'HEAD / HTTP/1.0\r\n\r' >&${hostA[1]}
cat <&${hostA[0]}

어쨌든, 두 명령을 모두 실행하게 되면 사용하지 말고 (항상 활성화되어 있는 것은 아님) socat를 사용하는 cat것이 좋습니다 ./dev/tcp

coproc hostA { socat - tcp:localhost:80; }

또는 명명된 파이프를 사용하여 bash에 대한 종속성을 제거할 수 있습니다.

mkfifo hostA.in hostA.out
socat - tcp:localhost:80 < hostA.in > hostA.out &

관련 정보