:TITLE: More channel I/O - fblocked & fconfigure
;#
;# RCSID: $Header: /home/cvs/TclTutor3/lesson/Tcl_English/Tcl_English42.lsn,v 1.2 2010/12/22 15:53:19 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# See file "NOTICE" for licensing terms.
;#
:LESSON_TEXT_START_LEVEL 0:
The <B>fblocked</B> and <B>fconfigure</B> commands provide more control over
the behavior of a channel.
<P>
The <B>fblocked</B> command checks whether a channel has returned all available
input.  It is useful when you are working with a channel that has been 
set to non-blocking mode and you need to determine if there should be data
available, or if the channel has been closed from the other end.
<P>
The <B>fconfigure</B> command has many options that allow you to query
or fine tune the behavior of a channel including whether the channel is
blocking or non-blocking, the buffer size,  the end of line character, etc.
<DL>
<B><DT>fconfigure</B> <I>channel ?param1? ?value1? ?param2? ?value2?</I>
<DD> Configures the behavior of a channel.  If no <I>param</I> values
are provided, a list of the valid configuration paramaters and their
values is returned.
<P>
If a single parameter is given on the command line, the value of that
parameter is returned.
<P>
If one or more pairs of <I>param/value</I> pairs are provided, those
parameters are set to the requested value.
<P>
Parameters that can be set include:

<DL>
<DT> -blocking <I>boolean</I>
<DD> Determines whether or not the task will block when
data cannot be moved on a channel.  (i.e. If no data is available on a
read, or the buffer is full on a write).

<DT> -buffering <I>type</I>
<DD> By default, I/O is fully buffered.  The type can be
  <DL>
    <DD> full
    <DT> Data is buffered until a buffer is full, the channel is closed or the
    channel is flushed.

    <DD> line
    <DT> Data is buffered until a newline character is encountered, and then flushed.

    <DD> none
    <DT> characters are sent to a device as soon as they are received.
  </DL>

<DT> -buffersize 
<DD> The number of bytes that will be buffered before
data is sent, or can be buffered before being read when data is received.
The value must be an integer between 10 and 1000000.

<DT> -translation 
<DD> Sets how Tcl will terminate a line when it
is output.  By default, the lines are teminated with the newline,
carriage return, or newline/carriage return that is appropriate to the
system on which the interpreter is running.  
<P>This can be configured to be:
  <DL>
  <DT> auto <DD> Translates newline, carriage return, or newline/carriage return
  as an end of line marker.  Outputs the correct line termination for the current
  platform.
  <DT> binary 
  <DD> Treats newlines as end of line markers.  Does not add any
  line termination to lines being output.
  <DT> cr <DD> Treats carriage returns as the end of line marker (and translates
  them to newline internally).  Output lines are terminated with a carriage return.
  This is the Macintosh standard.
  <DT> crlf <DD> Treats cr/lf pairs as the end of line marker, and terminates
  output lines with a carriage return/linefeed combination.  This is the
  Windows standard.
  <DT> lf <DD> Treats linefeeds as the end of line marker, and terminates
  output lines with a linefeed.  This is the
  Unix standard.
  </DL>
</UL>
</DL>


:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
The previous lessons have shown how to use channels with files and
blocking sockets.  Tcl also supports non-blocking reads and
writes, and allows you to configure the sizes of the I/O buffers,
and how lines are terminated.
<P>
A non-blocking read or write means that instead of a <B>gets</B> call
waiting until data is available, it will return immediately.  If there
was data available, it will be read, and if no data is available, the
<B>gets</B> call will return a 0 length.
<P>
If you have several channels that must be checked for input, you can
use the <B>fileevent</B> command to trigger reads on the channels, and then
use the <B>fblocked</B> command to determine when all the data is read.
<P>
The <B>fblocked</B> and <B>fconfigure</B> commands provide more control over
the behavior of a channel.
<P>
The <B>fblocked</B> command checks whether a channel has returned all available
input.  It is useful when you are working with a channel that has been 
set to non-blocking mode and you need to determine if there should be data
available, or if the channel has been closed from the other end.
<P>
The <B>fconfigure</B> command has many options that allow you to query
or fine tune the behavior of a channel including whether the channel is
blocking or non-blocking, the buffer size,  the end of line character, etc.
<DL>
<B><DT>fconfigure</B> <I>channel ?param1? ?value1? ?param2? ?value2?</I>
<DD> Configures the behavior of a channel.  If no <I>param</I> values
are provided, a list of the valid configuration paramaters and their
values is returned.
<P>
If a single parameter is given on the command line, the value of that
parameter is returned.
<P>
If one or more pairs of <I>param/value</I> pairs are provided, those
parameters are set to the requested value.
<P>
Parameters that can be set include:

<DL>
<DT> -blocking <I>boolean</I>
<DD> Determines whether or not the task will block when
data cannot be moved on a channel.  (i.e. If no data is available on a
read, or the buffer is full on a write).

<DT> -buffering <I>type</I>
<DD> By default, I/O is fully buffered.  The type can be
  <DL>
    <DD> full
    <DT> Data is buffered until a buffer is full, the channel is closed or the
    channel is flushed.

    <DD> line
    <DT> Data is buffered until a newline character is encountered, and then flushed.

    <DD> none
    <DT> characters are sent to a device as soon as they are received.
  </DL>

<DT> -buffersize 
<DD> The number of bytes that will be buffered before
data is sent, or can be buffered before being read when data is received.
The value must be an integer between 10 and 1000000.

<DT> -translation 
<DD> Sets how Tcl will terminate a line when it
is output.  By default, the lines are teminated with the newline,
carriage return, or newline/carriage return that is appropriate to the
system on which the interpreter is running.  
<P>This can be configured to be:
  <DL>
  <DT> auto <DD> Translates newline, carriage return, or newline/carriage return
  as an end of line marker.  Outputs the correct line termination for the current
  platform.
  <DT> binary 
  <DD> Treats newlines as end of line markers.  Does not add any
  line termination to lines being output.
  <DT> cr <DD> Treats carriage returns as the end of line marker (and translates
  them to newline internally).  Output lines are terminated with a carriage return.
  This is the Macintosh standard.
  <DT> crlf <DD> Treats cr/lf pairs as the end of line marker, and terminates
  output lines with a carriage return/linefeed combination.  This is the
  Windows standard.
  <DT> lf <DD> Treats linefeeds as the end of line marker, and terminates
  output lines with a linefeed.  This is the
  Unix standard.
  </DL>
</UL>
</DL>
</DL>
<P>
The example is similar to the lesson 40 example with a client and
server socket in the same script.  It shows a server channel being
configured to be non-blocking, and using the default buffering style -
data is not made avaialble to the script until a newline is present, or
the buffer has filled.
<P>
When the first write: <CODE>puts -nonewline $sock "A Test Line"</CODE> is
done, the <B>fileevent</B> triggers the read, but the <B>gets</B>
can't read characters because there is no newline.  The <CODE>gets</CODE>
returns a -1, and <CODE>fblocked</CODE> returns a 1.  When a bare
newline is sent, the data in the input buffer will become available,
and the <CODE>gets</CODE> returns <CODE>18</CODE>, and <CODE>fblocked</CODE>
returns 0.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
By default, <B>gets</B> and <B>puts</B> will wait until data can be
moved onto a channel or read from a channel before they return. This
is called <I>blocking</I> mode I/O, since the program is blocked
from running until the data is transfered.
<P>
This mode of operation can lead to deadlocks when two programs want
to write to each other via a shared channel, and neither can write
because the other hasn't read yet.
<P>
The <I>nonblocking</I> mode of I/O lets you escape from this dilemma
by starting a write, seeing that it fails, reading, and then writing
after the other program is ready to read.
<P>
The previous lessons have shown how to use channels with files and
blocking sockets.  Tcl also supports non-blocking reads and
writes, and allows you to configure the sizes of the I/O buffers,
and how lines are terminated.
<P>
A non-blocking read or write means that instead of a <B>gets</B> call
waiting until data is available, it will return immediately.  If there
was data available, it will be read, and if no data is available, the
<B>gets</B> call will return a 0 length.
<P>
If you have several channels that must be checked for input, you can
use the <B>fileevent</B> command to trigger reads on the channels, and then
use the <B>fblocked</B> command to determine when all the data is read.
<P>
The <B>fblocked</B> and <B>fconfigure</B> commands provide more control over
the behavior of a channel.
<P>
The <B>fblocked</B> command checks whether a channel has returned all available
input.  It is useful when you are working with a channel that has been 
set to non-blocking mode and you need to determine if there should be data
available, or if the channel has been closed from the other end.
<P>
The <B>fconfigure</B> command has many options that allow you to query
or fine tune the behavior of a channel including whether the channel is
blocking or non-blocking, the buffer size,  the end of line character, etc.
<DL>
<B><DT>fconfigure</B> <I>channel ?param1? ?value1? ?param2? ?value2?</I>
<DD> Configures the behavior of a channel.  If no <I>param</I> values
are provided, a list of the valid configuration paramaters and their
values is returned.
<P>
If a single parameter is given on the command line, the value of that
parameter is returned.
<P>
If one or more pairs of <I>param/value</I> pairs are provided, those
parameters are set to the requested value.
<P>
Parameters that can be set include:

<DL>
<DT> -blocking <I>boolean</I>
<DD> Determines whether or not the task will block when
data cannot be moved on a channel.  (i.e. If no data is available on a
read, or the buffer is full on a write).

<DT> -buffering <I>type</I>
<DD> By default, I/O is fully buffered.  The type can be
  <DL>
    <DD> full
    <DT> Data is buffered until a buffer is full, the channel is closed or the
    channel is flushed.

    <DD> line
    <DT> Data is buffered until a newline character is encountered, and then flushed.

    <DD> none
    <DT> characters are sent to a device as soon as they are received.
  </DL>

<DT> -buffersize 
<DD> The number of bytes that will be buffered before
data is sent, or can be buffered before being read when data is received.
The value must be an integer between 10 and 1000000.

<DT> -translation 
<DD> Sets how Tcl will terminate a line when it
is output.  By default, the lines are teminated with the newline,
carriage return, or newline/carriage return that is appropriate to the
system on which the interpreter is running.  
<P>This can be configured to be:
  <DL>
  <DT> auto <DD> Translates newline, carriage return, or newline/carriage return
  as an end of line marker.  Outputs the correct line termination for the current
  platform.
  <DT> binary 
  <DD> Treats newlines as end of line markers.  Does not add any
  line termination to lines being output.
  <DT> cr <DD> Treats carriage returns as the end of line marker (and translates
  them to newline internally).  Output lines are terminated with a carriage return.
  This is the Macintosh standard.
  <DT> crlf <DD> Treats cr/lf pairs as the end of line marker, and terminates
  output lines with a carriage return/linefeed combination.  This is the
  Windows standard.
  <DT> lf <DD> Treats linefeeds as the end of line marker, and terminates
  output lines with a linefeed.  This is the
  Unix standard.
  </DL>
</UL>
</DL>
</DL>
<P>
The example is similar to the lesson 40 example with a client and
server socket in the same script.  It shows a server channel being
configured to be non-blocking, and using the default buffering style -
data is not made avaialble to the script until a newline is present, or
the buffer has filled.
<P>
When the first write: <CODE>puts -nonewline $sock "A Test Line"</CODE> is
done, the <B>fileevent</B> triggers the read, but the <B>gets</B>
can't read characters because there is no newline.  The <CODE>gets</CODE>
returns a -1, and <CODE>fblocked</CODE> returns a 1.  When a bare
newline is sent, the data in the input buffer will become available,
and the <CODE>gets</CODE> returns <CODE>18</CODE>, and <CODE>fblocked</CODE>
returns 0.
:TEXT_END:

:CODE_START:

;# This is called when a server receives a connection
proc serverOpen {channel addr port} {
  puts "channel: $channel - from Address: $addr  Port: $port"
  puts "The default state for blocking is: [fconfigure $channel -blocking]"
  puts "The default buffer size is: [fconfigure $channel -buffersize ]"

  ;# Set this channel to be non-blocking.

  fconfigure $channel -blocking 0
  set bl [fconfigure $channel -blocking]
  puts "After fconfigure the state for blocking is: $bl"
  
  ;# Change the buffer size to be smaller

  fconfigure $channel -buffersize 12
  puts "After Fconfigure buffer size is: [fconfigure $channel -buffersize ]\n"

  ;# When input is available, read it.
  fileevent $channel readable "readLine Server $channel"
  }

;# A proc to read a line from a channel
proc readLine {who channel} {
  global didRead
  global blocked

  puts "There is input for $who on $channel"

  set len [gets $channel line]
  set blocked [fblocked $channel]
  puts "Characters Read: $len  Fblocked: $blocked"

  if {$len < 0} {
    if {$blocked} {puts "Input is blocked"
      } else {
      puts "The socket was closed - closing my end"
      close $channel;
      }
    } else {
    puts "Read $len characters:  $line"
    puts $channel "This is a return"
    flush $channel;
    }
  incr didRead;
  }

;# Set up a server to listen on port 33000
set server [socket -server serverOpen 33000]

after 120 update;	# This kicks MS-Windows machines for this application
;# connect to port 33000
set sock [socket 127.0.0.1 33000]

set bl [fconfigure $sock -blocking] 
set bu [fconfigure $sock -buffersize]
puts "Original setting for sock: Sock blocking: $bl buffersize: $bu"

fconfigure $sock -blocking No
fconfigure $sock -buffersize 8;

set bl [fconfigure $sock -blocking] 
set bu [fconfigure $sock -buffersize]
puts "Modified setting for sock: Sock blocking: $bl buffersize: $bu\n"

# Send a line to the server -- NOTE flush

set didRead 0
puts -nonewline $sock "A Test Line"
flush $sock;

# Loop until two reads have been done.

while {$didRead < 2} {
  ;# Wait for didRead to be set
  vwait didRead
  if {$blocked} {puts $sock "Newline" ; flush $sock; puts "SEND NEWLINE"}
  }
  
;# Read the return, and display it.
set len [gets $sock line]
puts "Return line: $len -- $line"
close $sock
vwait didRead
catch {close $server}
:TEXT_END:



