Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

stdin, stdout non bloquant comment apprendre ?

6 réponses
Avatar
Une Bévue
Je cherche à apprendre comment faire en sorte que stdin et stdout soient
non bloquant dans un configuration particulière.

Ce que je cherche à faire pour comprendre ma difficulté :

avoir un script (distant) qui réalise une sorte de hub lanceur de scripts.

le premier argument donne le script à lancer.

suivant le script à lancer d'autres arguments sont parfois nécessaie, là
je n'ai pas de problème pour filer les arguments au script choisi.

là où ça coince pour moi c'est quand le script lancé a besoin d'un
argument suplémentaire uniquement dans certains cas.

un exemple : j'ai un script "recettes" qui me télécharge une recette en
la dépouillant de toutes les pubs associées, puis range la recette dans
un répertoire qui est fonction d'une catégorie de recette genre "Entrée,
Plat ou Dessert", MAIS, quelquefois le script ne parvient pas
-automatiquement- à déterminer le type de recette il pose alors la
question à l'utilisateur.

C'est dans ce cas-là, c'est-à-dire quand je simule une entrée
utilisateur que tout se bloque.

si j'agis sur stdin avant stdout c'est OK
mais dès que je souhaite faire un stdin après un stdout ça bloque...

6 réponses

Avatar
blanc
Une Bévue wrote:
Je cherche à apprendre comment faire en sorte que stdin et stdout soient
non bloquant dans un configuration particulière.
Ce que je cherche à faire pour comprendre ma difficulté :
avoir un script (distant)

écrit dans quel langage ?
qui réalise une sorte de hub lanceur de scripts.
le premier argument donne le script à lancer.
suivant le script à lancer d'autres arguments sont parfois nécessaie, là
je n'ai pas de problème pour filer les arguments au script choisi.
là où ça coince pour moi c'est quand le script lancé a besoin d'un
argument suplémentaire uniquement dans certains cas.
un exemple : j'ai un script "recettes" qui me télécharge une recette en
la dépouillant de toutes les pubs associées, puis range la recette dans
un répertoire qui est fonction d'une catégorie de recette genre "Entrée,
Plat ou Dessert", MAIS, quelquefois le script ne parvient pas
-automatiquement- à déterminer le type de recette il pose alors la
question à l'utilisateur.

Comment fais-tu pour poser la question ?
Et pour saisir la réponse ?
C'est dans ce cas-là, c'est-à-dire quand je simule une entrée
utilisateur que tout se bloque.

Que veux-tu dire par "simuler" ? N'est-ce pas une vrai entrée que tu
souhaites faire ?
--
JiPaul.
/ /--/--// Jean-Paul Blanc
|/| L | quelquepart en (somewhere in)
/|| = ||| FRANCE
Avatar
Une Bévue
Le 30/06/2016 à 11:36, JiPaul a écrit :
écrit dans quel langage ?

Ruby
qui réalise une sorte de hub lanceur de scripts.
le premier argument donne le script à lancer.
suivant le script à lancer d'autres arguments sont parfois nécessaie, là
je n'ai pas de problème pour filer les arguments au script choisi.
là où ça coince pour moi c'est quand le script lancé a besoin d'un
argument suplémentaire uniquement dans certains cas.
un exemple : j'ai un script "recettes" qui me télécharge une recette en
la dépouillant de toutes les pubs associées, puis range la recette dans
un répertoire qui est fonction d'une catégorie de recette genre "Entrée,
Plat ou Dessert", MAIS, quelquefois le script ne parvient pas
-automatiquement- à déterminer le type de recette il pose alors la
question à l'utilisateur.


Comment fais-tu pour poser la question ?

bon, en ruby depuis le script lancé je fais un bête :
puts "Ma question"
Et pour saisir la réponse ?

pour saisir la réponse, je fais un gets
C'est dans ce cas-là, c'est-à-dire quand je simule une entrée
utilisateur que tout se bloque.


Que veux-tu dire par "simuler" ? N'est-ce pas une vrai entrée que tu
souhaites faire ?

Si si, mais pour l'instant, je simule une réponse au terminal, par un puts :
script appellant :
--------------------------------------------------------------------------------
#!/usr/bin/env ruby
# encoding: utf-8
# ~/dev/Ruby/non_blocking/popen3_simple_implementation_in_test.rb
$: << "#{ENV['HOME']}/bin/ruby_lib"
¾gin
How to Implement open3 > Simple implementation
http://coldattic.info/shvedsky/pro/blogs/a-foo-walks-into-a-bar/posts/62
=end
require 'rubygems'
def popen3(*cmd)
# Prepare pipes (get read and write ends)
in_r, in_w = IO.pipe
out_r, out_w = IO.pipe
err_r, err_w = IO.pipe
# Do the forking
child_pid = fork{
# This is the child
# Close the filehandlers that belong to the parent
# (we inherited them, as all the other)
in_w.close
out_r.close
err_r.close
# "Reopen" standard file handlers in the child context
#STDIN.reopen(in_w)
STDIN.reopen(in_r)
STDOUT.reopen(out_w)
STDERR.reopen(err_w)
# Do something in child context
ENV["ALTER_ENVIRONMENT"] = "for example"
# Now we're prepared to exec the command
exec(*cmd)
}
# This is the parent
# Close the filehandlers that belong to the child
in_r.close
out_w.close
err_w.close
in_w.printf "Entreen" #if out_r.read.chomp.end_with? '?'
#puts "out_r.read.chomp = #{out_r.read.chomp}"
return [in_w,out_r,err_r]
# We might as well do this (read below):
# return [in_w,out_r,err_r,child_pid]
end
@start = Time.now
# Test the function with own script avec demande
inp, out, err =
popen3("/Users/yt/dev/Ruby/non_blocking/popen3_simple_implementation_in_test_child.rb")
inp.close
question = out.read.chomp
puts "question :n|n#{question}n|"
¾gin
.-[:~/dev/Ruby/non_blocking]-[16-06-30 11:36:18]
'->$ ./popen3_simple_implementation_in_test.rb
question :
|
Type de recette ?
r_type = Entree
|
=end
--------------------------------------------------------------------------------
script appellé :
--------------------------------------------------------------------------------
#!/usr/bin/env ruby
# encoding: utf-8
# ~/dev/Ruby/non_blocking/popen3_simple_implementation_in_test_child.rb
$: << "#{ENV['HOME']}/bin/ruby_lib"
¾gin
How to Implement open3 > Simple implementation
http://coldattic.info/shvedsky/pro/blogs/a-foo-walks-into-a-bar/posts/62
=end
require 'rubygems'
puts "Type de recette ?"
r_type = gets.chomp
puts "r_type = #{r_type}"
--------------------------------------------------------------------------------
bon là, "ça roule" parce que je n'attends pas d'avoir la question pour
envoyer la réponse, ce qui n'est pas le but recherché...
le problème est que le out n'apparaît dans le script appellant que
lorsque le script lancé a fini.
ce que je voudrais, c'est, par exemple, en détectant un "?" savoir qu'il
y a une question posée est basculer d'out en in.
Avatar
Une Bévue
Le 30/06/2016 à 11:36, JiPaul a écrit :
Que veux-tu dire par "simuler" ? N'est-ce pas une vrai entrée que tu
souhaites faire ?

Si si, mais je la simule, pour l'instant.
bon en utilisant PTY, ça roule nettement mieux :
script appellant :
--------------------------------------------------------------------------------
#!/usr/bin/env ruby
# encoding: utf-8
# ~/dev/Ruby/non_blocking/with_pty.rb
$: << "#{ENV['HOME']}/bin/ruby_lib"
¾gin
Continuously read from STDOUT of external process in Ruby
http://stackoverflow.com/questions/1154846/continuously-read-from-stdout-of-external-process-in-ruby
=end
require 'rubygems'
require 'pty'
cmd =
"/Users/yt/dev/Ruby/non_blocking/popen3_simple_implementation_in_test_child.rb"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
# Do stuff with the output here. Just printing to show it works
i = 0
stdout.each do |line|
puts line.chomp + " (#{i})"
stdin.puts "Entree" if line.chomp.end_with? '?'
i += 1
end
#stdin.puts
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
--------------------------------------------------------------------------------
même script appelé que précédemment.
donc c'est déjà nettement mieux car je peux détecter le "?" de la
question et y répondre.
reste à remplacer la ligne :
stdin.puts "Entree" if line.chomp.end_with? '?'
par quelque chose du genre :
stdin.puts gets.chomp if line.chomp.end_with? '?'
avec le "gets.chomp" opérant sur le stdin du terminal...
le résultat actuel :
.-[:~/dev/Ruby/non_blocking]-[16-06-30 12:24:47]
'->$ ./with_pty.rb
Type de recette ? (0)
Entree (1)
r_type = Entree (2)
.-[:~/dev/Ruby/non_blocking]-[16-06-30 12:26:29]
'->$
Avatar
Une Bévue
Le 30/06/2016 à 12:33, Une Bévue a écrit :
reste à remplacer la ligne :
stdin.puts "Entree" if line.chomp.end_with? '?'
par quelque chose du genre :
stdin.puts gets.chomp if line.chomp.end_with? '?'
avec le "gets.chomp" opérant sur le stdin du terminal...

Bon ben avec un bête :
stdin.puts gets.chomp if line.chomp.end_with? '?'
script appellant modifié :
--------------------------------------------------------------------------------
#!/usr/bin/env ruby
# encoding: utf-8
# ~/dev/Ruby/non_blocking/with_pty.rb
$: << "#{ENV['HOME']}/bin/ruby_lib"
¾gin
Continuously read from STDOUT of external process in Ruby
http://stackoverflow.com/questions/1154846/continuously-read-from-stdout-of-external-process-in-ruby
=end
require 'rubygems'
require 'pty'
cmd =
"/Users/yt/dev/Ruby/non_blocking/popen3_simple_implementation_in_test_child.rb"
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
# Do stuff with the output here. Just printing to show it works
i = 0
stdout.each do |line|
puts line.chomp + " (#{i})"
#stdin.puts "Entree" if line.chomp.end_with? '?'
stdin.puts gets.chomp if line.chomp.end_with? '?'
### MODIFICATION ^^^^############################
i += 1
end
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
--------------------------------------------------------------------------------
mais bon, j'avoue ne pas comprendre "comment ça marche"...
au terminal j'ai maintenant :
.-[:~/dev/Ruby/non_blocking]-[16-06-30 12:40:04]
'->$ ./with_pty.rb
Type de recette ? (0)
Entree # <<<=== Ce que j'entre au terminal.
Entree (1)
r_type = Entree (2)
.-[:~/dev/Ruby/non_blocking]-[16-06-30 12:40:47]
'->$
me reste deux choses :
- comprendre
- emballer ça dans un socket
le but :
j'ai un socket sur un serveur auquel j'envoie une action (en fait le nom
d'un script) avec un paramètre depuis une autre bécanne
le socket lance le script sur le serveur avec le(s) paramètre(s)
et feedback la réponse à une question ***éventuelle*** à la bécanne
distante.
Avatar
Une Bévue
Sur une bécanne "mbp.local" le script appellant le socket :
#!/usr/bin/env ruby
# encoding: utf-8
# ~/bin/scripts/fdate.rb
$: << "#{ENV['HOME']}/bin/ruby_lib"
¾gin
Ruby Socket Programming
http://www.tutorialspoint.com/ruby/ruby_socket_programming.htm
=end
require 'socket'
hostname = "d620.local"
port = 2000
server = TCPSocket.open(hostname, port)
while line = server.gets
line = line.chop
puts line
case line
when /script/
script = $stdin.gets.chomp
server.puts script
when /type/
type= $stdin.gets.chomp
server.puts type
when /?$/ # line.include?('?') #
type= $stdin.gets.chomp
puts "Type entré : #{type}"
server.puts type
when /Au revoir !$/
break
end
end
server.close
ce qui donne au terminal :
.-[:~/bin/tests]-[16-06-30 13:58:16]
'->$ ./socket-client.rb
Quel script ?
socket-test
Script demandé : 'socket-test'.
cmd = '/home/yt/bin/tests/socket-test.rb'.
Type de recette ?
Entree
Type entré : Entree
Entree
r_type = Entree
^C./socket-client.rb:28:in `gets': Interrupt
from ./socket-client.rb:28:in `<main>'
.-[:~/bin/tests]-[16-06-30 14:00:19]
'->$
là comme j'ai la ligne :
r_type = Entree
cela signifie que le script appellé "socket-test" côté serveur de socket
a bien répondu.
reste à paeaufiner pour éviter un ^C.
Avatar
Une Bévue
Et côté "serveur" :
le socket :
#!/usr/bin/env ruby
# encoding: utf-8
require 'rubygems'
require 'pty'
require 'socket'
dir = '/home/yt/bin/tests'
server = TCPServer.open(2000)
loop { # Servers run forever
client = server.accept
client.puts "Quel script ?"
script = client.gets.chomp
puts "Script demandé : '#{script}'."
client.puts "Script demandé : '#{script}'."
cmd = "#{dir}/#{script}.rb"
puts "cmd = '#{cmd}'."
client.puts "cmd = '#{cmd}'."
begin
PTY.spawn( cmd ) do |stdout, stdin, pid|
begin
# Do stuff with the output here. Just printing to show it works
i = 0
stdout.each do |line|
puts line.chomp # + " (#{i})"
client.puts line.chomp #+ " (#{i})"
stdin.puts client.gets.chomp if line.chomp.end_with? '?'
#stdin.puts "Entree" if line.chomp.end_with? '?'
#stdin.puts gets.chomp if line.chomp.end_with? '?'
i += 1
end
#stdin.puts
rescue Errno::EIO
puts "Errno:EIO error, but this probably just means " +
"that the process has finished giving output"
end
end
rescue PTY::ChildExited
puts "The child process exited!"
end
}
le socket-test :
#!/usr/bin/env ruby
# encoding: utf-8
require 'rubygems'
puts "Type de recette ?"
r_type = gets.chomp
puts "r_type = #{r_type}"
et ce qu'il se passe au terminal :
┬─[:~/bin/tests]─[16-06-30 13:58:18]
╰─>$ ./socket-hub.rb
Script demandé : 'socket-test'.
cmd = '/home/yt/bin/tests/socket-test.rb'.
Type de recette ?
Entree
r_type = Entree
Errno:EIO error, but this probably just means that the process has
finished giving output
donc, ça roule "grosso-modo" des détails à mettre au point et
implémenter "pour de vrai"...