:TITLE: Channel I/O: socket, fileevent, vwait
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl40.lsn,v 1.5 2000/04/24 16:17:53 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:
Tcl I/O is based on a <I>channel</I>.  A channel is conceptually similar to
the <I>FILE *</I> in C, or a stream in shell programming.  The difference is
that a channel may be a either a stream device like a file, tape drive, or
tty, or a connection oriented construct like a socket.
<P>
A stream based channel is created with the <B>open</B> command, as discussed
in lesson 26.  A socket based channel is created with a <B>socket</B> command.
A socket can be opened either as a TCP client, or as a server.
<P>
When a channel exists, a handler can be defined that will be invoked when
the channel is available for reading or writing.  This handler is defined
with the <B>fileevent</B> command.
<P>

Finally, there is a command to wait until an event happens.  The
<B>vwait</B> command will wait until a variable is set.  This can be used
to create a semaphore style functionality for the interaction between client
and server.

<DL>
<B><DT>socket -server</B> <I>command ?options? port</I>
<DD> The <B>socket</B> command with the -server flag opens up a server
connecton on <I>port</I>.  When a connection occurs at <I>port</I>, the
proc <I>command</I> is called with the arguments:
<UL>
<LI>channel . . . . The channel for the new client
<LI>address . . . . The IP Address of this client
<LI>port. . . . . . . . The port that is assigned to this client
</UL>

<B><DT>socket</B> <I>?options? host port</I>
<DD> The <B>socket</B> command without the <B>-server</B> option opens
a client connection to the system with IP Address <I>host</I> and port
address <I>port</I>.  The IP Address may be given as a numeric string,
or as a fully qualified domain address.  
<P>
To connect to the local host, use the address 127.0.0.1 (the loopback
address).
<P>
<B><DT>fileevent</B> <I> channelId </I><B>readable</B> <I>?script?</I>
<B><DT>fileevent</B> <I> channelId</I><B> writeable</B> <I>?script?</I>
<DD>The <B>fileevent</B> command defines a handler to be invoked when a
condition occurs.  The conditions are <B>readable</B>, which invokes
<I>script</I> when a data is ready to be read on <I>channelId</I>, and
<B>writeable</B>, when <I>channelID</I> is ready to receive data.
<P>
<B><DT>vwait</B> <I>varName</I>
<DD> The <B>vwait</B> command pauses the execution of a script until
some background action sets the value of <I>varName</I>.  A background
action can be a proc invoked by a fileevent, or a socket connection,
or an event from a tk widget.
</DL>

:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:

 Tcl I/O is based on a <I>channel</I>.  A channel is conceptually
similar to the <I>FILE *</I> in C, or a stream in shell programming. 
The difference is that a channel may be a either a stream device like a
file, tape drive, or tty, or a connection oriented construct like a
socket. 

<P> A stream based channel is created with the <B>open</B> command, as
discussed in lesson 26.  A socket based channel is created with a
<B>socket</B> command. A socket can be opened either as a TCP client,
or as a server. 

<P> If a channel is opened as a server, then the tcl program will
'listen' on that channel for another task to attempt to connect with
it.  When this happens, a new channel is created for that link
(server-> new client), and the tcl program continues to listen for
connections on the original port number.  In this way, a single Tcl
server could be talking to several clients simultaneously. 

<P> When a channel exists, a handler can be defined that will be
invoked when the channel is available for reading or writing.  This
handler is defined with the <B>fileevent</B> command. When a tcl
procedure does a <B>gets</B> or <B>puts</B> to a blocking device, and
the device isn't ready for I/O, the program will block until the device
is ready.  This may be a long while if the other end of the I/O channel
has gone off line.  Using the <B>fileevent</B> command, the program
only accesses an I/O channel when it is ready to move data. 

<P> Finally, there is a command to wait until an event happens.  The
<B>vwait</B> command will wait until a variable is set.  This can be
used to create a semaphore style functionality for the interaction
between client and server, and let a controlling procedure know that an
event has occurred. 

<P> Look at the example, and you'll see the <B>socket</B> command being
used as both client and server, and the <B>fileevent</B> and
<B>vwait</B> commands being used to control the I/O between the client
and server. 

<P> Note in particular the <B>flush</B> commands being used.  Just as a
channel that is opened as a pipe to a command doesn't send data  until
either a <B>flush</B> is invoked, or a buffer is filled, the socket
based channels don't automaticly send data.   

<DL> <B><DT>socket -server</B> <I>command ?options? port</I> 
  <DD> The <B>socket</B> command with the -server flag opens up a server connecton on
<I>port</I>.  When a connection occurs at <I>port</I>, the proc
<I>command</I> is called with the arguments: 
  <UL> <LI>channel . . . .The channel for the new client 
    <LI>address . . . . The IP Address of this client 
    <LI>port. . . . . . . . The port that is assigned to this client 
    </UL>
 <B><DT>socket</B> <I>?options? host port</I>
    <DD> The <B>socket</B> command without the <B>-server</B> option opens
a client connection to the system with IP Address <I>host</I> and port
address <I>port</I>.  The IP Address may be given as a numeric string,
or as a fully qualified domain address.  
<P>
To connect to the local host, use the address 127.0.0.1 (the loopback
address).
<P>
<B><DT>fileevent</B> <I> channelId </I><B>readable</B> <I>?script?</I>
<B><DT>fileevent</B> <I> channelId</I><B> writeable</B> <I>?script?</I>
<DD>The <B>fileevent</B> command defines a handler to be invoked when a
condition occurs.  The conditions are <B>readable</B>, which invokes
<I>script</I> when a data is ready to be read on <I>channelId</I>, and
<B>writeable</B>, when <I>channelID</I> is ready to receive data.
<P>
<B><DT>vwait</B> <I>varName</I>
<DD> The <B>vwait</B> command pauses the execution of a script until
some background action sets the value of <I>varName</I>.  A background
action can be a proc invoked by a fileevent, or a socket connection,
or an event from a tk widget.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:

In order for a program to communicate to another program, machine, or
even a person, it has to open an I/O (Input/Output) channel to the
device that talks to the other entity.  By default most programs have a
connection to the display terminal and the keyboard.  In the simple case
of the "hello, World" program, the I/O channel is the output channel to
the display.
<P>
Tcl can open many kinds of channels.  It can open the simple stream
type I/O channels as was discussed in lesson 26, and it can open channels
to other machines on a network using the <B>socket</B> command.
<P>
Sockets come in two flavors: there are server sockets that wait for
someone to connect to them, and then process the input (like an NNTP
news server, or an SMTP mail server), and there are client sockets
that connect to the server socket and request to have it perform
an action.  Tcl can open socket I/O channels as either servers or
clients .
<P>
If a channel is opened as a server, then the tcl program will 'listen'
on that channel for another task to attempt to connect with it.  When
this happens, a new channel is created for that link (server-> new client),
and the tcl program continues to listen for connections on the original
port number.  In this way, a single Tcl server could be talking to several
clients simultaneously.
<P>
Once a channel exists, a handler can be defined that will be invoked
when the channel is available for reading or writing.  This handler is
defined with the <B>fileevent</B> command.
<P>
When a tcl procedure does a <B>gets</B> or <B>puts</B> to a blocking
device (for instance, doing a gets to the user's keyboard), and the
device isn't ready for I/O (ie: the user hasn't typed anything yet), the
program will block until the device is ready.  This may be a long while
if the other end of the I/O channel has gone off line.  Using the
<B>fileevent</B> command, the program only accesses an I/O channel when
it is ready to move data. 
<P>
Finally, there is a command to wait until an event happens.  The
<B>vwait</B> command will wait until a variable is set.  This can be used
to provide semaphore functionality, or to let a controlling procedure know
that an event has occurred.
<P>
Look at the example, and you'll see the <B>socket</B> command being
used as both client and server, and the <B>fileevent</B> and <B>vwait</B>
commands being used to control the I/O between the client and server.
<P>
Note in particular the <B>flush</B> commands being used.  Just as a
channel that is opened as a pipe to a command doesn't send data 
until either a <B>flush</B> is invoked, or a buffer is filled, the
socket based channels don't automaticly send data.  
<P>
The example defines two procs to handle events.  One of these is the
<B>serverOpen</B> proc, which will be called when the server receives a
connection.  The other is a <B>readLine</B> proc, that is declared to be
the input-available event handler by the <B>fileevent</B> command within
<B>serverOpen</B>.
<P>
When the code executes the line <B>puts $sock "A Test Line"</B>, it
sends the line to the server socket.  Receiving this input 
causes the execution to automaticly go to the <B>readLine</B> proc, which
reads the line from the server socket.
<P>
The code after the <B>puts</B> calls a <B>vwait</B> to wait until it 
knows that the line of data has been processed.  When <B>readLine</B>
has finished reading and displaying the line of data, it sends a
reply to the client socket, and sets <I>didRead</I>.  This lets
the main line code know it can continue processing, and <B>gets</B>
the reply.

<DL>
<B><DT>socket -server</B> <I>command ?options? port</I>
<DD> The <B>socket</B> command with the -server flag opens up a server
connecton on <I>port</I>.  When a connection occurs at <I>port</I>, the
proc <I>command</I> is called with the arguments:
<UL>
<LI>channel . . . . The channel for the new client
<LI>address . . . . The IP Address of this client
<LI>port. . . . . . . . The port that is assigned to this client
</UL>

<B><DT>socket</B> <I>?options? host port</I>
<DD> The <B>socket</B> command without the <B>-server</B> option opens
a client connection to the system with IP Address <I>host</I> and port
address <I>port</I>.  The IP Address may be given as a numeric string,
or as a fully qualified domain address.  
<P>
To connect to the local host, use the address 127.0.0.1 (the loopback
address).
<P>
<B><DT>fileevent</B> <I> channelId </I><B>readable</B> <I>?script?</I>
<B><DT>fileevent</B> <I> channelId</I><B> writeable</B> <I>?script?</I>
<DD>The <B>fileevent</B> command defines a handler to be invoked when a
condition occurs.  The conditions are <B>readable</B>, which invokes
<I>script</I> when a data is ready to be read on <I>channelId</I>, and
<B>writeable</B>, when <I>channelID</I> is ready to receive data.
<P>
<B><DT>vwait</B> <I>varName</I>
<DD> The <B>vwait</B> command pauses the execution of a script until
some background action sets the value of <I>varName</I>.  A background
action can be a proc invoked by a fileevent, or a socket connection,
or an event from a tk widget.
</DL>
:TEXT_END:

:CODE_START:
;# This is called when a server receives a connection

proc serverOpen {channel addr port} {
    global connected
    set connected 1
    fileevent $channel readable "readLine Server $channel"
    puts "OPENED"
}

proc readLine {who channel} {
    global didRead  
    if {[gets $channel line]<0} {
            fileevent $channel readable {}
            after idle "close $channel;set out 1"
    } else {        
            puts "READ LINE: $line"
            puts $channel "This is a return"
            flush $channel;
            set didRead 1
    }
}

set connected 0;
# catch {socket -server serverOpen 33000} server
set server [socket -server serverOpen 33000]

after 100 update;

set sock [socket -async 127.0.0.1 33000]
vwait connected

puts $sock "A Test Line"
flush $sock
vwait didRead
set len [gets $sock line]
puts "Return line: $len -- $line"

catch {close $sock}
vwait out
close $server

:TEXT_END:

