我正在使用TCL套接字命令在两个TCL / Tk应用程序之间进行通信,例如A和B,两者都有关联的GUI。 B上的服务器基本上接受来自A的命令并返回执行结果。问题是,一旦执行完成,B的GUI就会挂起。有没有办法让两个GUI独立工作?我使用以下脚本来设置两个应用程序之间的连接:
使用以下TCL脚本client.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}
其中server.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
目标是让用户继续使用GUI for A时,让B的GUI处于活动状态。这样,用户可以根据需要在两个GUI之间切换。 A和B都提供了不同的功能,可以处理需要同时提供的相同数据。
答案 0 :(得分:2)
您发布的代码有两个关键问题:
客户端在写完一段工作(即执行命令)后没有刷新它的套接字,因为出于性能原因,默认情况下非默认通道(不是stdin,stdout,stderr)是完全缓冲的。这可能导致服务器从未真正接收到命令。
服务器不通过fileevent
注册的脚本以非阻塞模式处理接受的套接字。
另外,您有一个小问题,如果您想要发送多行数据,您会发现您的协议不足。您可能会或可能不会关心这一点,并且有几种不同的方法可以解决这个问题。
处理客户的大问题的最佳方法是使用
fconfigure $cid -buffering none
打开插座后直接打开。这告诉Tcl应该立即将数据puts
发送到套接字上的通道。 (或者,使用line
而不是none
来获取行缓冲;在这种情况下,这也可以很好地工作。)您也可以进行显式刷新:
flush $cid
这将追溯到puts
。
最佳实践将使用更像这样的服务器脚本,其中一个过程用于设置已接受套接字连接的服务,另一个过程用于处理消息的读取和写入。接受过程(server
)关闭阻塞(并且通常也会调整缓冲),操作过程(readLine
)使用eof
和fblocked
来计算{gets
1}}成功或失败。
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 ...