Version 2 of chan pending

Updated 2010-07-03 08:51:09 by dkf
chan pending mode channelId

Returns the number of bytes in Tcl's buffers for the channel channelId in the direction specified by mode (which must be input or output).

This subcommand was introduced by TIP#287[L1 ].


How to use

The chan pending command is designed for use with non-blocking channels, especially sockets, and it is used to deal with the case where the source is producing far more data than was expected before delivering the boundary desired (typically a EOL character for gets).

proc accept {cb chan args} {
    global timeouts
    chan configure $chan -blocking 0 -buffersize 4096
    chan event $chan readable [list doGets $chan $cb]
    set ::timeouts($chan) ""
}
proc doGets {chan callback} {
    global timeouts
    if {[gets $chan line] >= 0} {
        after cancel $timeouts($chan)
        set timeouts($chan) ""
        {*}$callback $chan $line
    } elseif {[chan eof $chan]} {
        chan close $chan
        after cancel $timeouts($chan)
        unset timeouts($chan)
    } else {
        # Must be blocked; check for excessive buffering
        if {[chan pending input $chan] > 1024} {
            # must be a line longer than a kilobyte; naughty! reject
            chan close $chan
            after cancel $timeouts($chan)
            unset timeouts($chan)
        } elseif {$timeouts($chan) eq ""} {
            # no line timeout watcher; install one that waits 10 seconds
            # from when the start of the line arrives to when the end of the
            # line arrives before killing the channel
            set timeouts($chan) [after 10000 killChannel $chan]
        }
    }
}
proc killChannel chan {
    global timeouts
    unset timeout($chan)
    chan close $chan
}

# Make the (server) socket
socket -server [list accept processLineCallback] 12345
# This is where you'd add your code to handle each line
proc processLineCallback {chan line} {
    # ... whatever ...
    puts $chan-->$line
}