**Channel I/O: socket, fileevent, vwait** !!!!!! '''[Tcl Tutorial Lesson 39%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 41%|%Next lesson%|%]''' !!!!!! 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 [Tcl Tutorial Lesson 26%|%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. `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 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. ---- ***Example*** ====== # # Define two auxiliary procs # proc serverOpen {channel addr port} { global connected set connected 1 fileevent $channel readable [list 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 } } ====== The code to start the ''server'' and connect to it from a ''client'': ====== 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 ====== <> Resulting output: ======none OPENED READ LINE: A Test Line Return line: 16 -- This is a return ====== <> !!!!!! '''[Tcl Tutorial Lesson 39%|%Previous lesson%|%]''' | '''[Tcl Tutorial Index%|%Index%|%]''' | '''[Tcl Tutorial Lesson 41%|%Next lesson%|%]''' !!!!!!