[squeak-dev] reading and writing from STDIN and STDOUT

David T. Lewis lewis at mail.msen.com
Wed May 13 00:59:57 UTC 2009


On Tue, May 12, 2009 at 04:59:27PM -0400, Jason Rogers wrote:
> I am competing in a friendly Code Smackdown at work.  Smalltalk vs.
> All on-comers (Haskell, Erlang, LISP, Java, C and Python).  The
> challenge is to write a client for a Chinese Poker game.
> 
> Everything is going well except communicating with the Python-based
> server.  I am having trouble reading and writing from STDIN and
> STDOUT.  I've installed OSProcess which should give me access to these
> streams, but I don't see how to read one line at a time from STDIN and
> then get a handle on STDOUT to write a line.  Anyone have pointers or
> sample code?
> 
> Also, the image needs to be launched by Python with code like...
> 
>    subprocess.Popen(["/Application/Squeak/Contents/MacOS/Squeak VM
> Opt", "/Users/jrogers/Squeak/images/chinese_poker.image", "Squeak
> Client"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
> 
> This will obviously need to change for a server running on another OS.
>  The question I have here is how to start a process reading from STDIN
> as soon as the VM is fired up.  Should I just create an object that is
> waiting on STDIN, reading a line at a time, before saving the image?
> That way it would just keep trying to read when the image was fired up
> again.

Hi Jason,

I'm assuming that you are using OS X or other unix based OS (note
that OSProcess does not do pipes correctly on Windows, so you won't
be able to do that).

Please install CommandShell in addition to OSProcess, as that will give
you better ways to control external processes connected by pipes. I'm
not clear from your question as to whether Python or Squeak is the
"client" in this scenario, but it sounds like you will want to have
Squeak making requests to a Python server, but you want Python to
set up the pipes and invoke Squeak as a subprocess. I don't have
an example of this scenario exactly, but the following may help.

For an example of Squeak as the client, but where Squeak (not Python)
does all the work of setting up the pipes connections to the server,
see PipeableOSProcess class>>tkExample. This shows Squeak running
a tk/tcl interpreter and putting up a trivial UI with buttons connected
to Squeak.

For an example of Squeak as the server, communicating through its
STDIN and STDOUT streams (which might be pipes set up by Python in
your scenario), see class ExternalCommandShell. After evaluating
"ExternalCommandShell start" your Squeak image will read command
lines from STDIN and respond on STDOUT. The ExternalCommandShell
will evaluate input commands and Smalltalk expressions, returning
its output to the STDOUT stream. This does not sound like what you
want for your project, but it should give you an idea of how these
things can be done.

In general, the STDIN steam is "OSProcess thisOSProcess stdIn" and
the STDOUT and STDERR streams are "OSProcess thisOSProcess stdOut"
and "OSProcess thisOSProcess stdErr". Do not save these in variables,
but evaluate them at runtime so your Squeak image can find the right
input/output streams even after an image restart. That means you can
start a Process in Squeak that reads from stdIn and writes to stdOut.
Leave the process running when you save the image, and it will carry
on where it left off whenever your Python program restarts the Squeak
image.

Note that the stdIn stream for Squeak is (and must be) non-blocking in
order to prevent locking up the Squeak VM on a blocked read. That means
that your process will need to read available data from stdIn, possibly
looping until you get a complete string of whatever you are looking for.
For example, if ten characters are currently available in your STDIN
input stream, then "OSProcess thisOSProcess stdIn next: 10000" will
answer a string of length ten.

ExternalCommandShell does this all in an event-driven manner with
no polling, so you can copy that if you want to get fancy. Otherwise
a simple polling loop in your process will probably work well enough.
Put a 100 ms delay in whatever loop is reading from stdIn an you will
get tolerable performance.

Dave




More information about the Squeak-dev mailing list