从fileevent处理程序处理非全局变量

时间:2012-02-22 15:15:45

标签: tcl

有没有办法从fileevent处理程序中操作非全局变量?考虑以下最小服务器:

proc initState {stateName} {
    upvar $stateName state
    set state(foo) bar
    set state(baz) bla
    # ...
    return
}

proc handleConnection {stateName newsock clientAddress clientPort} {
    upvar $stateName state
    fconfigure $newsock -blocking 0
    fconfigure $newsock -buffering line
    fileevent $newsock readable [list handleData $newsock]
    return
}

proc handleData {f} {
    if {[eof $f]} {
        fileevent $f readable {}
        close $f
        return
    }
    gets $f line
    puts $f ok
    # need to modify state here...
    return
}

proc runServer {port} {
    array set state {}
    initState state
    socket -server {handleConnection state} $port
    vwait forever
}

runServer 1234

是否有可能操纵state范围内创建的runServer数组,或者是唯一可以使state成为全局变量的方法?

我对Tcl很新,如果我使用C,我只需将一个指向state的指针传递给事件处理程序,但遗憾的是Tcl不允许这样做。我在做什么奇怪的事情,是否有更多的Tcl-ish方式?

1 个答案:

答案 0 :(得分:4)

这根本不起作用。问题是Tcl的堆栈帧不会以您想要的方式持续存在。

解决此问题的标准选项是:

  1. 将状态保存在由“连接令牌”(例如,频道名称)索引的全局数组中。请记住,数组是按字符串索引的;像“sock42,hostname”这样的复合键非常合法。

  2. 将状态保存在以连接令牌命名的命名空间中。如果您使用的是Tcl 8.5,namespace upvar命令可以使更多更容易。

  3. 将状态保存在TclOO 对象(需要Tcl 8.6 单独的TclOO软件包8.5)或使用不同的对象系统(例如,[incr] Tcl],XOTcl;这些适用于许多Tcl版本。)

  4. 将状态保持在 coroutine (需要Tcl 8.6)。这有效地为您提供了一个命名堆栈(并允许您编写代码,因此它显然是“直线”而不是由回调驱动)但其版本要求是 strict