使用TCL套接字时挂起窗口



我使用TCL套接字命令在两个TCL/Tk应用程序之间进行通信,例如A和B,两者都有关联的GUI。B上的服务器基本上接受来自A的命令并返回执行结果。问题是,B的GUI在执行完成后立即挂起。是否有一种方法可以使两个GUI独立工作?我使用以下脚本设置两个应用程序之间的连接:

使用以下TCL脚本启动应用程序A。

proc execute { cmd } {
    set cid [socket localhost 9900]
    puts $cid $cmd
    while { [gets $cid line] >= 0 } {
        puts $line
    } 
    close $cid
}
set pid [exec B server.tcl &]
execute {puts HelloWorld}

服务器。tcl通过应用程序B设置服务器

proc server { cid addr port } {
     set cmd [gets $cid]
     catch $cmd result
     puts $cid result
     close $cid
}
socket -server server 9900
vwait forever

目标是让B的GUI处于活动状态,而用户继续使用a的GUI,这样用户就可以根据需要在两个GUI之间切换。对于需要同时提供的相同数据,A和B都提供了不同的功能

您发布的代码有两个关键问题:

  1. 客户端在写入工作(即要执行的命令)之后不会刷新它的套接字,因为出于性能原因,默认情况下,非默认通道(不是stdin, stdout, stderr)被完全缓冲。这可能导致服务器从一开始就没有真正接收到命令。

  2. 服务器不通过fileevent注册的脚本以非阻塞模式处理接受的套接字

还有一个小问题,如果你想发送多行数据,你会发现你的协议是不够的。你可能关心也可能不关心这个问题,有几种不同的方法可以解决这个问题。

关键问题1

处理客户大问题的最好方法是使用

fconfigure $cid -buffering none

直接打开插座。这告诉Tcl,它应该始终将数据通过puts发送到套接字上的通道。(或者,用line代替none来获得行缓冲;在这种情况下,这也足够好了。)您还可以执行显式刷新:

flush $cid

puts之后。

关键问题2

最佳实践将使用与此类似的服务器脚本,其中一个过程设置为接受的套接字连接提供服务,另一个过程处理消息的读写。接受过程(server)关闭阻塞(也经常调整缓冲),操作过程(readLine)使用eoffblocked来计算gets是否成功或失败。
proc server { cid addr port } {
    fconfigure $cid -blocking 0
    fileevent $cid readable "readLine $cid"
}
proc readLine { cid } {
    set cmd [gets $cid]
    if { [eof $cid] } {
        close $cid
    } elseif { ![fblocked $cid] } {
        catch $cmd result
        puts $cid $result
        close $cid
    }
}
socket -server server 9900
vwait forever

另一个问题

如果你真的这样做,另一个大问题是多行消息是有用的。您要么需要让上面的readLine累积行,直到它有一个完整的命令(appendinfo complete在这里有帮助),要么需要一些其他机制来处理数据传输。在生产代码中,更容易委托给像comm…

这样的包。