![Unix 파이프를 사용하여 REST 서비스로 데이터 스트리밍](https://linux55.com/image/140065/Unix%20%ED%8C%8C%EC%9D%B4%ED%94%84%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%98%EC%97%AC%20REST%20%EC%84%9C%EB%B9%84%EC%8A%A4%EB%A1%9C%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D.png)
기반으로다른 질문에 대한 답변stdout
요청된 엔터티로 프로세스의 스트림을 가져오기 위해 컬을 사용하고 있습니다 POST
.
myDataGeneratingApp \
| curl -H "Content-Type: application/json" -H "Transfer-Encoding: chunked" -X POST -d @- http://localhost:12000
EOF
불행하게도 컬은 데이터 전송을 시작하기 전에 표준 출력을 기다리고 있습니다. 내 응용 프로그램을 독립형으로 실행할 수 있고 데이터가 즉시 콘솔에 출력되기 때문에 이를 알고 있지만, 컬링하도록 파이프하면 서비스가 데이터 수신을 시작하기 전에 눈에 띄는 지연이 발생합니다.
애플리케이션 표준에서 사용할 수 있는 경우 컬을 사용하여 데이터를 즉시 스트리밍하려면 어떻게 해야 합니까? 컬에서 불가능하다면 다른 해결책(예: wget)이 있습니까?
답변1
컬 코드 찾아보기전송.c프로그램은 청크 프로토콜을 사용하여 요청 데이터(컬에서 서버로)를 다시 패키징할 수 있는 것처럼 보입니다. 여기서 각 데이터 청크에는 ASCII 16진수 청크 길이가 앞에 붙고 \r\n
.
서버에 연결되면 스트리밍을 통해 이용 가능한 것으로 보입니다 -T -
. 다음 예를 고려하십시오.
for i in $(seq 5)
do date
sleep 1
done |
dd conv=block cbs=512 |
strace -t -e sendto,read -o /tmp/e \
curl --trace-ascii - \
-H "Transfer-Encoding: chunked" \
-H "Content-Type: application/json" \
-X POST -T - http://localhost/...
이 스크립트는 5개의 데이터 청크를 파이프로 보냅니다. 각 청크는 날짜로 시작하고 dd
512바이트로 채워져 strace
파이프 curl -T -
를 읽습니다. 터미널에서 우리는 볼 수 있습니다
== Info: Connected to localhost (::1) port 80 (#0)
=> Send header, 169 bytes (0xa9)
0000: POST /... HTTP/1.1
001e: Host: localhost
002f: User-Agent: curl/7.47.1
0048: Accept: */*
0055: Transfer-Encoding: chunked
0071: Content-Type: application/json
0091: Expect: 100-continue
00a7:
<= Recv header, 23 bytes (0x17)
0000: HTTP/1.1 100 Continue
전송된 연결과 헤더를 보여줍니다. 특히 , 헤더가 curl
제공 되지 않고 서버(아파치)가 응답한 헤더가 제공됩니다 . 그 뒤에는 데이터의 처음 512바이트(16진수 200)가 옵니다.Content-length:
Expect:
Continue
=> Send data, 519 bytes (0x207)
0000: 200
0005: Fri Sep 14 15:58:15 CEST 2018
0045:
0085:
00c5:
0105:
0145:
0185:
01c5:
=> Send data, 519 bytes (0x207)
출력 파일에는 strace
파이프라인의 각 타임스탬프가 표시되고 연결에 기록됩니다.read
sendto
16:00:00 read(0, "Fri Sep 14 16:00:00 CEST 2018 "..., 16372) = 512
16:00:00 sendto(3, "200\r\nFri Sep 14 16:00:00 CEST 20"..., 519, ...) = 519
16:00:00 read(0, "Fri Sep 14 16:00:01 CEST 2018 "..., 16372) = 512
16:00:01 sendto(3, "200\r\nFri Sep 14 16:00:01 CEST 20"..., 519, ...) = 519
16:00:01 read(0, "Fri Sep 14 16:00:02 CEST 2018 "..., 16372) = 512
16:00:02 sendto(3, "200\r\nFri Sep 14 16:00:02 CEST 20"..., 519, ...) = 519
16:00:02 read(0, "Fri Sep 14 16:00:03 CEST 2018 "..., 16372) = 512
16:00:03 sendto(3, "200\r\nFri Sep 14 16:00:03 CEST 20"..., 519, ...) = 519
16:00:03 read(0, "Fri Sep 14 16:00:04 CEST 2018 "..., 16372) = 512
16:00:04 sendto(3, "200\r\nFri Sep 14 16:00:04 CEST 20"..., 519, ...) = 519
16:00:04 read(0, "", 16372) = 0
16:00:05 sendto(3, "0\r\n\r\n", 5, ...) = 5
보시다시피, 둘 사이의 간격은 1초로, 데이터가 수신되는 동시에 전송되고 있음을 나타냅니다. 데이터를 읽는 중이므로 전송하려면 최소한 512바이트가 있어야 합니다 fread()
.
답변2
아래 편집 내용을 참조하세요
당신이 원하는 것은 불가능합니다. POST 데이터를 보내려면 길이를 알아야 하므로 curl
먼저 전체 데이터를 읽어서 길이를 파악해야 합니다.
Transfer-Encoding: chunked
이 제한을 우회하는 방법이지만 서버의 응답에만 해당됩니다.
그 이유는 chunked
HTTP/1.1에서만 지원되는데, 요청을 보낼 때 클라이언트는 서버가 HTTP/1.1을 이해하는지 알 수 없기 때문입니다. 답변과 함께 메시지가 왔지만 요청을 보내기에는 너무 늦었습니다.
편집하다
wget 매뉴얼에 따르면 이는 wget의 제한사항인 것 같습니다.
Wget은 POST 데이터의 크기를 미리 알아야 합니다. 따라서 --post-file에 대한 인수는 일반 파일이어야 합니다. FIFO 또는 /dev/stdin과 같은 항목을 지정하면 작동하지 않습니다. HTTP/1.0에 내재된 제한 사항을 해결하는 방법은 아직 명확하지 않습니다. HTTP/1.1에서는 요청 길이를 미리 알 필요가 없는 청크 전송을 도입했지만 클라이언트는 HTTP/1.1 서버와 통신하고 있다는 사실을 알지 못하면 청크를 사용할 수 없습니다. 응답을 받을 때까지 이를 알 수 있는 방법이 없으며, 응답을 받으려면 요청이 완료되어야 합니다. 이는 닭고기와 달걀 문제입니다.
문제가 존재하지만 인식됩니다.RFC 7230:
클라이언트는 서버가 HTTP/1.1(또는 그 이상) 요청을 처리할 것이라는 사실을 알지 않는 한 전송 인코딩을 포함하는 요청을 보내면 안 됩니다. 이러한 지식은 특정 사용자 구성의 형태이거나 이전에 수신된 응답의 버전을 기억함으로써 가능합니다. .
따라서 청크된 POST 데이터를 보내는 것이 가능하며 다른 답변에서 볼 수 있듯이 컬은 이미 이를 지원합니다.