jeudi 5 mars 2015

Linux (named) pipes several experiments leads to confusion


Hello I've come across various articles and SO questions and I am still confused about something that I use on daily basis, but never realized how confusing it can be. I am experimenting with (named) pipes in Linux.


1st try was simple: figure out how pipe buffers are working:



#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
ctrl+c
#3
cat /tmp/mypipe


Observation: When I killed echo before cat reads the data nothing was written to pipe (cat keeps running but nothing was read from pipe). I was assuming that when you type producent >named_pipe and you will exit producent then part of data that match pipe buffer size will be written to named_pipe and will remain here until it will be read by consument (now I know that this is not how it works). So what I did next was:


2nd try was to connect consument to other end of pipe:



#1
mkfifo /tmp/mypipe
#2
echo "Hello World" >/tmp/mypipe
#3
cat /tmp/mypipe


Observation: cat command displays the "Hello World" message and both processes ends. The interesting discovery here was that during the #2 step ps -elf does not display the echo command. It seems that echo is waiting until somebody will read from pipe and this is explanation why nothing was printed to pipe in my first attempt.


3rd try was to pipe command that will run "forever" and constantly write to pipe and see what will happened:



#1
mkfifo /tmp/mypipe
#2
yes >/tmp/mypipe
#3
cat /tmp/mypipe


Observation: This worked as expected and cat printed out what yes forwarded to pipe. However I have tried to replace cat with tail -f. When I did this then tail did not print anything until the yes command was killed.


4th try is the big mystery:



# 1#
mkfifo /tmp/mypipe

# 2#
for i in $(seq 1 10000); do echo -n $i"|"> /tmp/mypipe; done

# 3#
for i in $(seq 1 10); do echo "${i}# Read:"; cat /tmp/mypipe && echo ""; done


After this the 3# command start typing something like that:



1# Read:
1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|
2# Read:
109|
3# Read:
110|
4# Read:
111|
5# Read:
112|
6# Read:
113|114|115|
7# Read:
116|
8# Read:
117|
9# Read:
118|119|120|121|122|123|124|125|126|127|128|129|130|131|132|133|134|135|136|137|138|139|140|141|142|143|144|145|146|147|148|149|150|151|152|153|154|155|156|157|158|159|160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175|176|177|178|179|180|181|182|183|184|185|186|187|188|189|190|191|192|193|194|195|196|197|198|199|200|201|202|203|204|205|206|207|208|209|210|211|212|213|214|215|216|217|218|219|220|221|222|223|224|225|226|227|228|229|230|231|232|233|234|235|236|237|238|239|240|241|242|243|244|245|246|247|248|249|250|251|252|253|254|255|256|257|258|259|260|261|262|263|264|265|266|267|268|269|270|271|272|273|274|275|276|277|278|279|280|281|282|283|284|285|286|287|288|289|290|291|292|293|294|295|
10# Read:
296|297|298|299|300|301|302|303|304|305|306|307|308|309|310|311|312|313|314|315|316|317|318|319|320|321|322|323|324|325|326|327|328|329|


Questions:


1st and 2nd try:



  1. Are the named pipes equivalent to classic | pipes as they are knows e.g. from bash in this particular case?

  2. Does producent always wait for consument? If yes then what is purpose of pipe buffers? Is this behavior known as blocking communication?


  3. How does Linux know when the consument is connected to pipe and thus when the communication can happen? I've tried lsof named_pipe but it gives me nothing, where is this information stored? I have also try following and result was that cat cannot read from pipe.


    #1


    mkfifo /tmp/mypipe


    #2


    echo 1 >/tmp/mypipe


    #3


    rm /tmp/mypipe


    #4


    mkfifo /tmp/mypipe


    #5


    cat /tmp/mypipe




  4. Is typing: producent >/tmp/mypipe the equivalent of typing command | I mean the situation when somebody wants to pipe one command to another but forget to type another command after pipe (ps in this case also did not show first command)?




3rd try:



  1. What is difference between cat and tail -f in this particular case?


4th try:




  1. What is going on here? Why the chunks of read data are not the exact size? I was expecting output as:


    1# Read:


    1|


    2# Read:


    2|


    3# Read:


    3|




PS: Also I have tried different order of starting commands (reading first and writing after) but the result was the same.


PPS: I hope this is clear but: Producer = process that writes to pipe. Consumer = process that reads from pipe.


Is this possible explain to guy which has mostly scripting knowledge with bit of C? Thank you very much.



Aucun commentaire:

Enregistrer un commentaire