두 개의 직렬 포트(ttyS0 및 ttyUSB0)가 있는 두 대의 컴퓨터가 있습니다. (실제로는 같은 컴퓨터에 있지만 이는 테스트용일 뿐입니다.) 이 포트는 널 모뎀 케이블을 통해 연결됩니다. 나는 단순히 바이트를 한쪽 끝으로 보내고 다른 쪽 끝으로 보내거나 그 반대로 보낼 수 있기를 원합니다. 다음은 왜 작동하지 않습니까? :
# set both serial ports to 9600 8n1
# `-parenb` means no parity,
# `-cstopb` means 1 stop bit
# cs8 means 8 bits at a time
stty -F /dev/ttyUSB0 cs8 -cstopb -parenb 9600
stty -F /dev/ttyS0 cs8 -cstopb -parenb 9600
# in one terminal:
echo "asdf" > /dev/ttyUSB0
# in another terminal, this hangs and does nothing
cat < /dev/ttyS0
andpipe netcat
(아래)와 비슷한 작업을 쉽게 수행할 수 있으므로 위와 같은 작업도 가능할 것 같습니다.
mkfifo mypipe
# in one terminal
cat < mypipe
# in another. works as expected
echo "asdf" > mypipe
답변1
다음은 왜 작동하지 않습니까?
# in one terminal:
echo "asdf" > /dev/ttyUSB0
# in another terminal, this hangs and does nothing
cat < /dev/ttyS0
일반적으로 직렬 포트는 데이터를 버퍼링하지 않기 때문입니다. 클라이언트 애플리케이션이 직렬 포트에 도착하는 바이트를 수신하지 않으면 해당 바이트는 단순히 삭제됩니다.
실험적으로 수신 컴퓨터에서 다른 직렬 터미널 프로그램을 시작한 minicom
다음 전송 컴퓨터에서 명령을 다시 실행해 보십시오. 전송 속도와 프레임이 일정하다고 가정하면 대상에 "asdf"가 나타나는 것을 볼 수 있습니다.cu
echo
답변2
나는 단순히 바이트를 한쪽 끝으로 보내고 다른 쪽 끝으로 보내거나 그 반대로 보낼 수 있기를 원합니다. 다음은 왜 작동하지 않습니까?
순서를 바꾸면 되기 때문인 것 같습니다. 리스너 시작첫 번째그리고그 다음에데이터 보내기(파이프 예제에서 했던 것처럼 - 듣기 시작합니다.첫 번째):
# Absolutely first, configure each port using `stty`, as you already
# do:
# set both serial ports to 9600 8n1
# `-parenb` means no parity,
# `-cstopb` means 1 stop bit
# cs8 means 8 bits at a time
stty -F /dev/ttyUSB0 cs8 -cstopb -parenb 9600
stty -F /dev/ttyS0 cs8 -cstopb -parenb 9600
# THEN, do in this order
# first, in the receiving terminal, start listening
cat < /dev/ttyS0
# then, in a separate terminal for sending, send the data
echo "asdf" > /dev/ttyUSB0
나는 내 대답이 다음과 같다고 확신한다.프로그램정답, 의미: 맹목적으로 따르면 효과가 있을 것입니다.
그러나 문제는 여전히 남아 있습니다.왜? 왜 먼저 듣기 시작해야합니까? Linux 커널 버퍼링이 당신을 위한 것이 아닌가요? 그렇다면 데이터를 읽기 위해 버퍼에 배치하면 안 되나요? 분명히 그렇죠아니요, 그렇지 않으면 먼저 쓴 다음 읽어도 괜찮습니다. 그러나 그것은 사실이 아니다.
나는 여기서 추측하고 있지만 여기서 대답은 드라이버가 데이터를 수신할 때 먼저 수신 더미 파일이 /dev/ttyUSB0
열려 있고 다른 프로세스에 의해 열려 있는지 확인한다는 것입니다. 만약에아니요, 데이터를 받을 사람이 없기 때문에 드라이버는 데이터를 폐기합니다. 만약 파일예open - 파일을 연 프로세스가 버퍼링된 데이터를 읽을 수 있도록 허용합니다.
직렬 포트를 통한 전송과 IPC(프로세스 간 통신) 파이프를 통한 전송의 주요 차이점
이는 make 파이프라인을 사용하는 파이프라인 예시와 다릅니다 mkfifo
. 방금 확인했습니다. 파이프라인 예에서는 먼저 터미널에서 듣기를 시작할 수 있습니다.또는먼저 다른 터미널의 파이프로 보냅니다. 그것은 중요하지 않습니다. 두 경우 모두에서 작동합니다.
먼저 쓰는 경우 쓰기가 차단되고 프로세스가 파이프에서 데이터를 읽을 때까지 기다립니다. 먼저 읽으면 읽기가 차단되고 프로세스가 파이프에 쓸 때까지 기다립니다. 이는 bash의 기반이 거의 확실한 mkfifo()
Linux C 함수 문서에서 확인됩니다 .mkfifo
바라보다man 3 mkfifo
(강조하다):
이런 방식으로 FIFO 특수 파일이 생성되면 모든 프로세스에서 일반 파일처럼 읽거나 쓰기 위해 해당 파일을 열 수 있습니다. 단, 양쪽 끝이 열려 있어야 합니다. 동시에입력이나 출력을 진행하기 전에 그것에 대해 작업하십시오. 읽기를 위해 FIFO 열기보통 블록 다른 프로세스가 쓰기를 위해 동일한 FIFO를 열 때까지 또는 그 반대의 경우도 마찬가지입니다.
그러나 이는 직렬 포트의 동작과 다릅니다. 아마도 각 끝의 직렬 포트가 다음과 같이 표시되어야 하기 때문일 것입니다.다른기계는 FIFO 파이프와 달리 읽기 및 쓰기 끝을 제어해야 합니다.같은 기계에서. 후자의 경우 커널은 한 프로세스가 읽기를 시도하는 동안 다른 프로세스가 쓰기를 시도하는 시점을 쉽게 추적할 수 있습니다. 파이프의 양쪽 끝을 제어하여 두 프로세스 중 하나를 차단할 수 있기 때문입니다.
그러나 직렬 포트의 경우 커널은 다른 장치가 수신 대기 중이거나 전송을 원하는지 알 수 없으므로 전송을 차단하지 않습니다. 명확하게 말하면 파이프에 쓸 때 리스너가 나타날 때까지 쓰기가 차단됩니다. 그러나 직렬 포트에 쓸 때 컴퓨터는리스너가 존재하는지 확인할 수 없습니다., 그래서절대 차단하지 마세요!그냥 보냅니다.수신기가 없으면 차단이 발생하지 않지만, 아무도 듣고 있지 않은 동안 직렬을 통해 전송된 데이터는 손실됩니다.다시 말하지만, 이것은 파이프와 동일하지 않습니다. 내 실험과 위의 문서는 프로세스가 파이프를 통해 데이터를 전송하려고 시도하고 있음을 확인합니다.데이터를 읽을 수 있는 리스너가 존재할 때까지 차단됩니다.
참조 및 "참조":
- 이 글을 쓰면서 나는 나의 다양한 발견들을 적극적으로 연구하고 기록하고 있다.eRCAGuy_dot파일관심이 있으시면 여기에서 다시 구매하시기 바랍니다:직렬 터미널_README.md.
- 내 데모 코드:eRCaGuy_hello_world/bash/ipc_pipe_fifo.sh
man 3 mkfifo
:https://man7.org/linux/man-pages/man3/mkfifo.3.html