我使用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都提供了不同的功能
您发布的代码有两个关键问题:
-
客户端在写入工作(即要执行的命令)之后不会刷新它的套接字,因为出于性能原因,默认情况下,非默认通道(不是stdin, stdout, stderr)被完全缓冲。这可能导致服务器从一开始就没有真正接收到命令。
-
服务器不通过
fileevent
注册的脚本以非阻塞模式处理接受的套接字
还有一个小问题,如果你想发送多行数据,你会发现你的协议是不够的。你可能关心也可能不关心这个问题,有几种不同的方法可以解决这个问题。
关键问题1
处理客户大问题的最好方法是使用
fconfigure $cid -buffering none
直接打开插座。这告诉Tcl,它应该始终将数据通过puts
发送到套接字上的通道。(或者,用line
代替none
来获得行缓冲;在这种情况下,这也足够好了。)您还可以执行显式刷新:
flush $cid
在puts
之后。
关键问题2
最佳实践将使用与此类似的服务器脚本,其中一个过程设置为接受的套接字连接提供服务,另一个过程处理消息的读写。接受过程(server
)关闭阻塞(也经常调整缓冲),操作过程(readLine
)使用eof
和fblocked
来计算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
累积行,直到它有一个完整的命令(append
和info complete
在这里有帮助),要么需要一些其他机制来处理数据传输。在生产代码中,更容易委托给像comm…