Version 10 of A little client-server example

Updated 2010-05-27 06:53:04 by hae

Richard Suchenwirth 2006-02-28 - The following very simple script can act as either the server or the client of a socket connection:

  • When called with "server" as first argument, it listens on the given port. Lines coming in are evaluated, and the result is sent back
  • Otherwise, the script is a client: takes lines from stdin, sends them to the server, displays the result

 set host localhost
 set port 9900

 if {[lindex $argv 0] eq "server"} {
    puts "Server started..."
    socket -server server $port
 } else {
    set chan [socket $host $port]
    fconfigure $chan -buffering line
    fileevent $chan readable [list client'read $chan]
    fileevent stdin readable [list client'send $chan]
 }

#-----------------------------------------------------

 proc server {chan addr port} {
    fconfigure $chan -buffering line ;# NOT -blocking 0 (see below!)
    while {[gets $chan line]>=0} {
        catch $line res
        puts $line->$res ;# local logging
        puts $chan $res
    }
    close $chan
 }

#------------------------------------------------------

 proc client'read chan {
    if {[eof $chan]} {close $chan; exit}
    gets $chan line
    puts <-$line
 }
 proc client'send chan {
    gets stdin line
    puts $chan $line
 }

#------------------------------------------------------

 vwait forever

RS 2008-09-26 - Years (and possibly some "security" patches) later, this code runs no more on Win XP - the server starts up and waits, but clients get an EOF before they can even send something. Does anyone have an idea what could lead to this changed behavior?

MS seems to recall that XP's firewall also blocks connections to localhost.

RS 2008-10-02: no, it was something different.. someone edited -blocking 0 into the server fconfigure. Taking that out again, it now works like it always did, at least on Windows XP :^)

Lars H: That means it operates in a rather unusual fashion, though. The server can only serve one connection at a time, since it sits in the server while loop rather than the event loop. How about

 proc server {chan addr port} {
    fconfigure $chan -buffering line -blocking 0
    fileevent $chan readable [list server_eval $chan]
 }
 proc server_eval {chan} {
    if {![eof $chan]} then {
        gets $chan line
        catch $line res
        puts $line->$res ;# local logging
        puts $chan $res
    } else {
        close $chan
    }
 }

?


See also: