Domanda

I am writing a bash script and I was looking for something that will allow me to send commands to a file that the program would read and perform. And I found this. From the beginning I started to experiment I realized that there is one big trouble: if the input line is about 100 characters there is a ~50% chance of that the reading from the other side will fail. Let me explain on example what happens.

To begin with, we need a fifo and two one-liners for server and client respectively.

# creating fifo
mkfifo pipe

# a-la server
while true; do \
    echo -n 'Send to client: > ';\
    read ;\
    echo "$REPLY" > pipe ;\
    read answer < pipe ;\
    echo "Got answer: $answer" ;\
done

# a-la client
while read < pipe; do \
    echo 'Finished reading.';\
    echo "FROM SERVER: $REPLY" ;\
    echo ACK > pipe ;\
done

Assuming we did all this in $HOME there shouldn’t be a need to check if does the pipe exist yet or not. So, in simple cases like ‘123’ or ‘where are the errors?’ it goes fine. But if you try to copy a five-line paragraph from any article on wikipedia to send it to client, it will fail.

Example of what we could get:

Server:

Send to client: > 123
Got answer: ACK
Send to client: > авление Вашаклахуун-Уб’аах-К’авииля отметилось возведением множества построек в столице царства. Были сооружены Храм 16, Храм 20, Храм 21, Храм 22 (посвящённый двадцатилетию со дня коронации этого правителя[31]), окончательная версия местного стадиона для игры в мяч, а также святилище Эсмеральда, украшенное большой Иероглифической лестницей, излагающей историю Шукуупа. Стоит также отметить, что при Вашаклахуун-Уб’аах-К’авииле резко изменился стиль в монументальной скульптуре. Его стелы, установленные после 710 года (а именно Стелы C, F, 4, H, A, B и D), отличаются пластичностью и раскованно
Got answer: ÐÐм множе²°ÐÐÑÑÑÐÐÐ ²ÑÑÐÐÐÑÐ °²° »¸ÑÐÐÑÑÐÐÐÑ ¥°¼1,ÐÑÐÐ 0 ¥°¼2,ÐÑÐÐ 2(¿¾²½½¹ÐÐÐÐÑÐÑÐÐÐÑÐÑÑÐ ÐÐÑ º¾¾½°¸¸ÑÑÐÐÐ ¿°²¸µ»3], ÐÐÐÐÑÐÑÐÐÑÐÐÑ ²µ¸ÐÐÑÑÐÐÐÐ °´¸¾½°ÐÐÑ ¸³Ð ¼ °ÑÐÐÐÐ ²¸»¸µÐÑÐÐÑÐÐÑÐÐ,ÑÐÑÐÑÐÐÐÐÐ ±¾»¾¹ÐÐÑÐÐÐÐÑÐÑÐÑÐÐÐ »µ½¸µ¹ ¸·»°³°щµ¹ÐÑÑÐÑÐÑ ¨º¿° ¡¾¸ÑÐÐÐÐ ¾¼µ¸ ¾ÐÑÐ °°º»°½ÐÐ♰°Ð♰²¸¸»µÑÐÐÐÐ ¸·¼µ½¸»ÑÑлÐ ¼¾½¼µ½°»½¾¹ÑÐÑÐÑÐÑÑÑÐ.ÐÐÐ µ»ы, устан¾²»µ½½µÐÐÑÐÐ 1 ³¾´°(°ÐÐÐÐÐÐ ¡µ»C ,4 ,A  ¸D,ÐÑÐÐÑÐÑÑÑÑ ¿»°¸½¾Ð °º¾ÐÐÐÐ
Send to client: >

And on client there is only:

Finished reading.
FROM SERVER: 123

It looks like server starts reading right after he sends its data, so client barely able to read something from the pipe. In the example above he wasn’t been able to read anything. And this all also breaks text in multibyte encoding.

Put simply, it goes like that

  1. server sends: aaaaaaaa… -this is a very long line - …aaaaaabcbcbcbc
  2. server reads: aaaa… …abcbbc
  3. /actually goes at the same time with #2/ client reads what server had not managed to read yet: aaccb

In order to make server wait before trying to read the "ACK" from client, I’ve tried to change pipe’s file permissions to make them act as a semaphore. The results were interesting.

Since we can’t manipulate the permission to read (because once forbidden from the server, client won’t be able to read from the pipe) we’ll switch the -w flag.

Here are modified versions of client and server. NB change in redirection after the read command on the client.

# a-la server
chmod 644 pipe ;\
while true; do \
    echo -n 'Send to client: > ';\
    read ;\
    echo "$REPLY" > pipe ;\
    chmod -w pipe ;\
    until [ -w pipe ]; do \
        echo 'Waiting client to read what we sent' ;\
        sleep 1 ;\
    done ;\
    read answer < pipe ;\
    echo "Got answer: $answer" ;\
done

# a-la client
chmod 644 pipe ;\
set -x ;\
while read <>pipe; do \
    echo 'Finished reading.' ;\
    chmod u+w pipe ;\
    echo $? ;\
    ls -l pipe &>/dev/null ;\
    echo "FROM SERVER: $REPLY" ;\
    echo ACK > pipe ;\
done

chmod 644 is here to be sure the pipe had right permissions whichever script you start first.

set -x in order to see the fun that will be there.

Redirection in client changed to <> due to read-write locks on the pipe. I’m not sure how do they work, but reading on a client with read <pipe doesn’t work after write permissions were disabled on the server.

Make sure your paragraph is big enough so the code echoing ‘Waiting client to read what we sent’ executes.

I’m not actually going to send that big data, I just think that accidental lag in I/O may be the reason of this bug appearing even on short phrases.

Now the question: why, if you remove the ls command, it stops working on big data?

My bash version: GNU bash, version 4.2.45(1)-release (x86_64-pc-linux-gnu)

È stato utile?

Soluzione

A named pipe is just a one-way communication stream: anything that's written into it by any process will be read out of it by some process. You have two processes (server and client) writing into it and two processes reading out of it, so you have no guarantees about which process sees which input.

You want two-way communication: you want your client to see only what the server writes, and your server to see only what the client writes. For that, you need to create two named pipes: one that the server writes into and the client reads from, and one that the client writes into and the server reads from.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top