| ActiveTcl User Guide |

# Channel I/O: socket, fileevent, vwait

Tcl I/O is based on a the concept of channels. A channel is conceptually similar to a `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, 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 as either as a client, or as a server.

If a socket 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 automatically send data.

`socket -server` `command` `?options?` `port`
  The `socket` command with the `-server` flag starts a server socket listing on port `port`. When a connection occurs on `port`, the proc `command` is called with the arguments:
  - `channel` - The channel for the new client
  - `address` - The IP Address of this client
  - `port` The port that is assigned to this client
`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 data is ready to be read on `channelID`, and `writeable`, when `channelID` is ready to receive data. Note that end-of-file must be checked for by the `script`.
`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.

## Examples

    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