[Bezoar] 2017-12-17 I looked in the wiki and the man page for a simple example that does not require a web server and could not find a good simple example to try out the tcllib websockets package. I did some testing on my own and cobbled together something that works and I hope people find it instructive. Luckily the websockets lib is native tcl code so I was able to determine that it is always necessary to specify a subprotocol even it its nonsense to get the websocket library to connect. With this example you can connect either via the commandline client or the html page with multiple instances. What ever you type will show up on all connectons. Also you will see pings on the commandline client. So below I have the server first, A web page you can load into your browser to test it out or a command line client using the websocket client side. The server runs on port 9900. The client assumes localhost but the javascript in the html page will get the correct origin if you serve the page from a web server. I got the html code from the testsuite of another websocket library and modified it to work using the file:// protocol. I would give attribution but its been a while and I cannot remember where I got it. I was also using the latest version of Tcllib. Note the html connects on load so start server before loading the html into a browser window or alternatively just refresh the browser after starting server. Server #!/bin/sh # the next line restarts using wish \ exec /opt/usr8.6.3/bin/tclsh8.6 "$0" ${1+"$@"} package require websocket proc handler { sock type msg } { switch -glob -nocase -- $type { co* { puts "Connected on $sock" } te* { puts "RECEIVED: $msg" foreach s $::openSockets { ::websocket::send $s $type ">$msg" } } cl* - dis* - error { set idx [ lsearch $::openSockets $sock ] if { $idx >= 0 } { set ::openSockets [lreplace $::openSockets $idx $idx ] } catch { close $sock } } default { puts "$type" } } } proc readline { fd handler } { set line [ gets $fd ] if { [eof $fd ] } { catch { close $fd } } uplevel #0 $handler \"$line\" } proc test { sock line } { ::websocket::send $sock text $line } proc closeapp { sock } { ::websocket::close $sock 1000 "normal close" after 1000 { exit 0 } } proc readAll { sock } { global servSock set count 0 array set data {} set mode request while { [gets $sock line ] != -1 } { if { $line eq "\n" || $line eq "" } { continue; } if { $count > 0 } { set mode headers } append data($mode) "$line\n" incr count } lassign $data(request) method url proto set header [ dict create ] foreach line [split $data(headers) \n ] { set idx [string first ":" $line ] if { $idx == -1 } { continue; } set key [string range $line 0 $idx-1 ] set value [string trim [ string range $line $idx+1 end ] ] puts "'$key' | '$value'" dict set header $key $value } if { $url eq "/log/me" } { puts "got a websocket request : $url" puts "header: $header" set wtest [::websocket::test $servSock $sock /log/me $header ] if { $wtest } { ::websocket::upgrade $sock ::websocket::takeover $sock handler 1 puts "[::websocket::conninfo $sock type] from [::websocket::conninfo $sock sockname] to [::websocket::conninfo $sock peername]" fileevent $sock readable lappend ::openSockets $sock } else { puts "did not get a valid web socket request: url : $url" set reply "$proto 404 Not Found\r\nContentType: text/html\r\n\r\n

Not a web server!

" puts $sock $reply catch { close $sock} } } else { puts "did not get a web socket request: url : $url" set reply "$proto 404 Not Found\r\nContentType: text/html\r\n

Not a web server!

" puts $sock $reply catch { close $sock} } } ::websocket::loglevel debug proc Server {startTime channel clientaddr clientport} { puts "Connection from $clientaddr registered" set now [clock seconds] fconfigure $channel -blocking 0 -buffering line fileevent $channel read [list readAll $channel ] } global openSockets set openSockets {} set servSock [ socket -server [list Server [clock seconds]] 9900 ] ::websocket::server $servSock ::websocket::live $servSock /log/me handler vwait forever Command Line Client #!/bin/sh # the next line restarts using wish \ exec /opt/usr8.6.3/bin/tclsh8.6 "$0" ${1+"$@"} package require websocket ::websocket::loglevel info proc handler { sock type msg } { switch -glob -nocase -- $type { co* { puts "Connected on $sock" } te* { puts "RECEIVED: $msg" } cl* - dis* - error { puts " $type" catch { close $sock } exit 0 } default { puts "$type" } } puts -nonewline stdout ">" flush stdout } proc readline { fd handler } { set line [ gets $fd ] if { $line eq "q" } { exit 0 ; # harsh but this is an example after all } if { [eof $fd ] } { catch { close $fd } } uplevel #0 $handler \"$line\" } proc test { sock line } { ::websocket::send $sock text $line } proc closeapp { sock } { ::websocket::close $sock 1000 "normal close" after 1000 { exit 0 } } fconfigure stdin -blocking 0 -buffering line set sock [::websocket::open http://localhost:9900/log/me handler -protocol s ] fileevent stdin read [list readline stdin [list test $sock ] ] puts "[::websocket::conninfo $sock type] from [::websocket::conninfo $sock sockname] to [::websocket::conninfo $sock peername]" puts -nonewline stdout ">" flush stdout vwait forever Browser Client a page you can load up in your browser without using a server use the file:/// syntax . Chat Example
<>Enter Category Here