:TITLE: Channel I/O: socket, fileevent, vwait ;# ;# RCSID: $Header: /cvsroot/tcl/tcltutorial/original/Tcl40.lsn,v 1.1 2004/11/04 16:01:14 davidw 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 channel. A channel is conceptually similar to the FILE * 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.

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

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 fileevent command.

Finally, there is a command to wait until an event happens. The vwait 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.

socket -server command ?options? port
The socket command with the -server flag opens up a server connecton on port. When a connection occurs at port, the proc command is called with the arguments:
socket ?options? host port
The socket command without the -server option opens a client connection to the system with IP Address host and port address port. The IP Address may be given as a numeric string, or as a fully qualified domain address.

To connect to the local host, use the address 127.0.0.1 (the loopback address).

fileevent channelId readable ?script?
fileevent channelId writeable ?script?
The fileevent command defines a handler to be invoked when a condition occurs. The conditions are readable, which invokes script when a data is ready to be read on channelId, and writeable, when channelID is ready to receive data.

vwait varName
The vwait command pauses the execution of a script until some background action sets the value of varName. A background action can be a proc invoked by a fileevent, or a socket connection, or an event from a tk widget.
:TEXT_END: :LESSON_TEXT_START_LEVEL 1: Tcl I/O is based on a channel. A channel is conceptually similar to the FILE * 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.

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

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.

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 fileevent command. When a tcl procedure does a gets or puts 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 fileevent command, the program only accesses an I/O channel when it is ready to move data.

Finally, there is a command to wait until an event happens. The vwait 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.

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

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

socket -server command ?options? port
The socket command with the -server flag opens up a server connecton on port. When a connection occurs at port, the proc command is called with the arguments:
socket ?options? host port
The socket command without the -server option opens a client connection to the system with IP Address host and port address port. The IP Address may be given as a numeric string, or as a fully qualified domain address.

To connect to the local host, use the address 127.0.0.1 (the loopback address).

fileevent channelId readable ?script?
fileevent channelId writeable ?script?
The fileevent command defines a handler to be invoked when a condition occurs. The conditions are readable, which invokes script when a data is ready to be read on channelId, and writeable, when channelID is ready to receive data.

vwait varName
The vwait command pauses the execution of a script until some background action sets the value of varName. A background action can be a proc invoked by a fileevent, or a socket connection, or an event from a tk widget.
: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.

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 socket command.

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 .

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.

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 fileevent command.

When a tcl procedure does a gets or puts 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 fileevent command, the program only accesses an I/O channel when it is ready to move data.

Finally, there is a command to wait until an event happens. The vwait 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.

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

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

The example defines two procs to handle events. One of these is the serverOpen proc, which will be called when the server receives a connection. The other is a readLine proc, that is declared to be the input-available event handler by the fileevent command within serverOpen.

When the code executes the line puts $sock "A Test Line", it sends the line to the server socket. Receiving this input causes the execution to automaticly go to the readLine proc, which reads the line from the server socket.

The code after the puts calls a vwait to wait until it knows that the line of data has been processed. When readLine has finished reading and displaying the line of data, it sends a reply to the client socket, and sets didRead. This lets the main line code know it can continue processing, and gets the reply.

socket -server command ?options? port
The socket command with the -server flag opens up a server connecton on port. When a connection occurs at port, the proc command is called with the arguments:
socket ?options? host port
The socket command without the -server option opens a client connection to the system with IP Address host and port address port. The IP Address may be given as a numeric string, or as a fully qualified domain address.

To connect to the local host, use the address 127.0.0.1 (the loopback address).

fileevent channelId readable ?script?
fileevent channelId writeable ?script?
The fileevent command defines a handler to be invoked when a condition occurs. The conditions are readable, which invokes script when a data is ready to be read on channelId, and writeable, when channelID is ready to receive data.

vwait varName
The vwait command pauses the execution of a script until some background action sets the value of varName. A background action can be a proc invoked by a fileevent, or a socket connection, or an event from a tk widget.
: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: