나는 소켓을 수신하고, 명령을 받아들이고, 작업을 수행하는 작은 UDP 서버를 PHP로 작성했습니다. 이것은 실제로 매우 기본적인 것입니다. 다음과 같이 수동으로 연결할 수 있습니다.
% nc -u host port
(여기서 nc = Ncat: 버전 7.50(https://nmap.org/ncat))
명령을 입력하면 결과 응답이 표시됩니다. 효과가있다정확히명령줄에서 작동하길 원하는 방식입니다.
그러나 다음과 같은 파일을 "cat"하면 다음과 같습니다.
cat FILE| nc -u host port
또는 다음과 같이 데이터를 보내십시오.
echo "command1\ncommand2\n" | nc -u host port
...그리고 내 PHP 애플리케이션은 줄 끝 문자를 포함하여 모든 것을 한 번에 읽습니다. 그냥 끝까지 읽어보고 싶네요.
물론 파일 내용을 감싸서 각 줄을 nc로 보낼 수 있습니다.
for x in `cat <file>`; do
echo $x | nc -u host port
done
...하지만 그건 완전 낭비예요. 나는 nc에 1개의 연결을 원합니다. 많지는 않습니다.
PHP 애플리케이션에서 출력을 인쇄할 때 다음과 같이 표시되기 때문에 EOL 문자를 문자열에 넣습니다. command1 command2...하지만 모두 하나의 문자열에 있습니다.
대화형 모드가 비대화형 모드와 다르게 동작하는 이유는 무엇입니까?
오후 내내 노력했지만 제대로 작동하지 않는 것 같습니다.
분명 설명이 있을 거에요.
귀하가 제공할 수 있는 모든 정보에 감사드립니다.
추신: PHP 코드의 기본은 다음과 같습니다.
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_bind($sock, '0.0.0.0', 2000);
for (;;) {
socket_recvfrom($sock, $cmd, 1024, 0, $ip, $port);
echo "command is $cmd";
$reply = process($cmd);
echo "reply is $reply";
socket_sendto($sock, $reply, strlen($reply), 0, $ip, $port);
}
nc를 사용하여 대화형으로 텍스트를 입력할 때 CTRL-D를 눌러 패킷을 분리할 수 있습니다. 쉘 스크립트에서 동일한 작업을 수행하는 경우:
printf 'command1\0014commandd2\0014'| nc -u host port
...이러한 명령은 모두 하나의 명령으로 나타납니다.
PHP 코드의 패킷 크기를 5로 줄인 다음 20바이트 길이의 데이터를 보내면 데이터가 잘리고 분리되지 않습니다.
혹시 버퍼링 문제일지도 모른다고 온라인에서도 준비했습니다. 나는 다음을 사용하려고합니다 :
stdbuf -oL -eL cat FILE | nc -u host port
...하지만 놀랍게도 이것도 별 차이가 없었습니다.
마지막으로, 그렇게 하면 다음과 같은 사실을 발견했습니다.
for x in command1 command2; do
echo $x
sleep 1
done | nc -u host port
…모든 것이 계획대로 진행되었습니다. 서버는 첫 번째 명령을 받은 다음 두 번째 명령을 받습니다.
정말 불분명한 것은 수면 1이 효과가 있는 이유입니다. 꺼내면 실패합니다. 위의 내용은 모든 에코를 nc로 보내는 것보다 확실히 낫습니다.
답변1
l0b0은 문제를 해결했지만 다른 사항에 대한 답변은 다음과 같습니다.
물론 파일의 내용을 감싸서 각 줄을 nc:로 보낼 수도 있지만
for x in $(cat <file>); do echo $x | nc -u host port; done
그것은 완전한 낭비입니다. 나는 NC에 1개의 연결을 원합니다. 많지는 않습니다.
1) 실제로 파일의 줄을 보내지 않고 공백으로 구분된 내용을 보냅니다. 공백은 개행, 탭 또는 공백일 수 있습니다(IFS를 변경하지 않은 경우). 이러한 명령은 "명령"에 대한 이해가 한 단어로 제한되는 경우에만 동일하지만 일반적으로 대부분의 Unix(y) 명령은 여러 단어입니다. 이러한 단어는 쉘 경로 이름 확장(종종 "globbing"이라고도 함)을 위해 처리되므로 ?*[..]
에 대한 값이 포함되어 있으면 $x
파일의 값과 다를 수 있습니다.
2) UDP는 연결이 없고 전혀 연결이 없기 때문에 연결이 "낭비"되지 않습니다. 어쩌면 당신은 원하지 않는다는 뜻일 수도 있습니다실행절차적 nc
(로컬)
대화형 모드가 비대화형 모드와 다르게 동작하는 이유는 무엇입니까?
입력하다단말기Unix에서는 일반적으로 한 번에 한 줄씩 처리합니다. 프로그램(여기서는 nc
)이 작업을 수행할 때 read
Enter(또는 이에 상응하는 키)를 누른 후 다음을 입력할 때까지 원하는 수의 문자를 입력할 때까지 기다리고 선택적으로 편집합니다. ( nc
패킷으로 보내기 위해) 프로그램에 전달됩니다 . (프로그램의 버퍼가 너무 작지 않은 한, 적합한 부분만 전송되고 나머지 부분은 다음 읽기를 위해 대기합니다.) 선택적으로 이 기능을 끌 수 있으며 각 문자(또는 프로그램에 의해 생성된 문자 그룹) 단일 키 입력) - 및 와 같은 프로그램에서 사용할 수 있도록 몇 가지(예: 기능 키)를 별도로 제공할 수 있지만 vi
덜 명확합니다 bash
. 공식적으로는 이렇게 불린다."정규" 및 "비정규" 모드, 그러나 역사적으로 비표준 패턴은 "원시"로 설명되고 표준 패턴은 "요리된" 패턴으로 설명되었습니다.
다른 유형의 파일(파이프 포함)에서 데이터를 읽으면 줄 바꿈(예: 줄 바꿈)을 무시하고 버퍼에 맞는 모든 내용을 읽습니다. 사용자의 경우 여러 줄이 포함되어 있습니다.
nc를 사용하여 대화형으로 텍스트를 입력할 때 CTRL-D를 눌러 패킷을 분리할 수 있습니다. 쉘 스크립트에서 동일한 작업을 수행하면
printf 'command1\0014commandd2\0014'| nc -u host port
...모든 명령이 하나의 명령으로 나타납니다.
3) 터미널의 Control-D는 특별합니다. 보다 정확하게는 eof
터미널 드라이버에 설정된 대로 구성된 문자(일반적으로 Control-D이지만 변경 가능)가 특별합니다. 입력하는 대로이것프로그램이 문자를 읽는 동안 반환을 기다리거나 데이터에 control-D를 포함하지 않고 읽기가 종료됩니다. 파일에 control-D가 나타날 때 해당 문자 코드는 특별하지 않습니다.
4) 그리고 당신이 생성하는 캐릭터는 어쨌든 Ctrl-D가 아닙니다. Control-D는 \004
많은 버전 echo
과 일부 다른 상황에서 사용되는 \x04
8진수 표기법 입니다. Control-A는 STX라고도 알려져 있으며 Unix에서는 실제로 사용되지 않습니다( \001
여러 가상 터미널 창 간 전환을 제어하는 데 사용하는 프로그램 제외).screen
혹시 버퍼링 문제일지도 모른다고 온라인에서도 준비했습니다. 나는 다음을 사용해 보았습니다.
stdbuf -oL -eL cat FILE | nc -u host port
...그러나 놀랍게도 이것도 아무런 차이가 없었습니다.
5) stdbuf
C 라이브러리 "stdio" 루틴에만 영향을 미치며, cat
텍스트 및 텍스트가 아닌 "바이너리" 데이터를 모두 처리하도록 설계되었으므로 이러한 루틴을 사용할 수 없습니다. 가장 편리한 테스트 시스템(CentOS6)에서 strace
GNU-coreutils-8.4가 cat
영향을 받지 않음 을 확인했지만 stdbuf
다른 구현이 영향을 받을 수 있다는 점을 배제할 수는 없습니다. sed '' file; grep '' file; awk 1 file
내가 확인한 것처럼 텍스트를 줄 단위로 처리하도록 설계된 프로그램을 사용하면 stdbuf -oL
차이가 발생합니다 .
그러나 그것은 당신이 원하는 변화를 가져오지 못할 수도 있습니다. 파이프에 라인을 추가하는 작성기 프로그램과 nc
이를 읽고 보내는 것 사이에 경쟁 조건이 있을 수 있으며, 작성기가 더 빠르면 여전히 여러 줄을 하나의 나가는 패킷으로 묶을 것입니다.
마침내 나는 이렇게 하면
for x in command1 command2; do echo $x; sleep 1; done | nc -u host port
모든 것이 계획대로 진행될 것임을 깨달았습니다. 서버는 첫 번째 명령을 받은 다음 두 번째 명령을 받습니다.정말 불분명한 것은 수면 1이 효과가 있는 이유입니다. ...
6) 이는 경쟁 조건을 방지합니다. 쉘이 파이프에 한 줄을 쓸 때마다 nc
쉘이 다음에 쓰기 전에 그것을 읽고 보낼 시간이 확실히 있습니다.
답변2
귀하의 코드는 대부분 거기에 있으며, 지금 해야 할 일은 $cmd
코드를 개행으로 끝나는 문자열의 대기열로 처리하는 것뿐입니다. 나는 오랫동안 PHP를 작성하지 않았기 때문에 일반 Python 의사 코드를 사용했습니다.
input = ''
try:
first_command, remaining_input = input.split('\n', 1)
execute(first_command)
input = remaining_input
except ValueError:
# No newline yet; we have to wait for more input
input = socket.receive()
이렇게 하면 애플리케이션이 사용되는 방식이 아닐 수도 있는 입력 스트림과 단일 대화형 명령을 처리할 수 있습니다.