次に示す server.tcl と client.tcl は,それぞれが名前の通りサーバとそのク ライアントで,先に server.tcl を起動しておき client.tcl がそれにアクセス するという形になります.
server.tcl 中の socket -server でサーバとしての動作を開始します.引数は, ソケット接続されたときに呼び出されるプロシージャとポート番号です.ここで の例では暫定的に 8823 を使いました.呼び出しプロシージャとして指定したの は serverAdd です.呼び出し時には引数が3つ付加されます.それぞれ,接続 ソケット ID,ホストアドレス,ポート番号となります.
起動後は vwait で無限ループを構成して他のクライアントからの接続を待ちま す.
server_add 中では,ソケットが読みだし可能になったときに呼び出されるプロ シージャの登録とバッファリングの設定,という2つのことを行っています.登 録されるプロシージャは serverHandle としました.また,バッファリングは 行単位で行われるようにしています.一般的にサーバとの通信は行単位となって いるので,この点で整合性があります.
server_handle は登録したとおり,ソケットが読み出し可能となると呼ばれます. 内部の処理としては,ソケットから行を読み出す,EOF なら終了,何かコマンド があればそれに応じた処理をする,となります.ここでは単にクライアントから 送られて来た文字列をそのまま送り返す処理としています.
client.tcl で server.tcl のサーバへアクセスします.まず,socket によりソ ケットを指定したホスト,ポート番号で開きます.そして,サーバ側と同様にソ ケットが読み出し可能になったときに呼ばれるプロシージャを登録し,そのバッ ファリングを行単位に指定します.プロシージャは clientHandle として登録し ています.
clientHandle 中でも,行を読み込み,EOF なら終了,応答があればそれに従っ て処理をする,という形をとります.
send コマンドは Tcl/Tk アプリケーションでなければ使用できませんが,ソケッ トによれば,サーバ/クライアントが容易に構築でき,また,その各々は言語を 選びません.そして,ネットワーク上の別のホストとの通信が可能である利点が あります.
ソケットの扱いがこれほど簡単にできるとは思いませんでしたが,これも Tcl/Tk のお手軽な強力さを表しているのかもしれません.
#!/usr/local/bin/tclsh proc serverAdd {sock addr port} { fileevent $sock readable "serverHandle $sock" fconfigure $sock -buffering line } proc serverHandle {sock} { set line [gets $sock] if {[eof $sock]} { close $sock } else { puts $sock "test from server: $line" } } socket -server serverAdd 8823 vwait forever
#!/usr/local/bin/tclsh proc clientHandle {sock} { if {[gets $sock str] < 0} { catch {close $sock} exit } else { puts $str } } if {[catch {socket localhost 8823} sock] != 0} { puts "Cannot open socket 8823" exit } fileevent $sock readable "clientHandle $sock" fconfigure $sock -buffering line foreach str $argv { puts $sock $str } vwait forever