close

close channelId ?r(ead)|w(rite)?'

DESCRIPTION

This Tcl command closes the channel given by channelId.

ChannelId must be an identifier for an open channel such as a Tcl standard channel (stdin, stdout, or stderr), the return value from an invocation of open or socket, or the result of a channel creation command provided by a Tcl extension.

If r (or read) is present and channelId was opened bidirectionally, then the channel will be “half-closed” so that it becomes only possible to write to it. Conversely with w (or write) which closes the reader side of a bidirectional channel. This is particularly useful with a pipe or socket.

If the open command was run with "|COMMAND", that is, as a pipeline, close waits until the command is terminated. If the command finished with error - by the same rules as with exec command - then the same kind of Tcl error will be generated at the call to close command. BEWARE! This will not happen, if the channel for the pipeline has been set nonblocking mode (by fconfigure $fd -blocking 0) - in this case the close command will always succeed. Remember to set the pipeline channel back to blocking before doing close, if you want to detect the commandline error.

MAN PAGE

https://www.tcl-lang.org/man/tcl/TclCmd/close.htm

SEE ALSO

file, open, socket, eof, channel, exec, stderr

EXAMPLES

 set fh [open output.txt r]
 set data [read $fh]
 close $fh

LV What are the ramifications if you don't close a file in Tcl? Any? I assume a memory leak in long running daemon type apps...

Lazy people might want to have a look at autoclose EF.


glennj: When working with pipes (i.e. [set pipe [open "| some command"]]]), and the pipe is blocking (i.e. [fconfigure $pipe -blocking yes] which is the default), then [close $pipe] throws an error if the command exited with non-zero status or if the command sent any output to stderr.

example:

 set command {sh -c {echo "to stdout"; echo >&2 "to stderr"; exit 42}}
 set pipe [open "| $command"]
 set standard_output [read -nonewline $pipe]
 set exit_status 0
 if {[catch {close $pipe} standard_error] != 0} {
     global errorCode
     if {"CHILDSTATUS" == [lindex $errorCode 0]} {
         set exit_status [lindex $errorCode 2]
     }
 }
 puts "exit status is $exit_status"
 puts "captured standard output: {$standard_output}"
 puts "captured standard error: {$standard_error}"

Output is:

 exit status is 42
 captured standard output: {to stdout}
 captured standard error: {to stderr}

AMG: TIP #332 "Half-Close for Bidirectional Channels" [L1 ] adds an optional argument to specify which direction of the channel to close, like the shutdown(2) system call [L2 ].

close channel ?read|write?


Lordmundi (2011-04-05): My google searches haven't been very fruitful, but is there any way to detect that a peer closed the connection before issuing the close on the socket?

For example, I have a tcl web server which works will with most browsers, but when using wget, apparently it (wget) will close the socket as soon as it sees 404 in the header. So after i'm done writing all this output information to the socket, when i run close $sock i get an error saying "connection reset by peer".

I'd like to be able to detect this if I could, but eof $sock doesn't return true and neither does fblocked $sock. Should I just wrap the close in a catch and forget about it? Or is there some cleanup i should be doing if the client closes the socket ahead of me?