使用TCL插座时挂窗

时间:2013-01-05 19:34:01

标签: sockets tcl tk

我正在使用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都提供了不同的功能,可以处理需要同时提供的相同数据。

1 个答案:

答案 0 :(得分:2)

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

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

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

  3. 另外,您有一个小问题,如果您想要发送多行数据,您会发现您的协议不足。您可能会或可能不会关心这一点,并且有几种不同的方法可以解决这个问题。

    关键问题1

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

    fconfigure $cid -buffering none
    
    打开插座后直接打开。这告诉Tcl应该立即将数据puts发送到套接字上的通道。 (或者,使用line而不是none来获取行缓冲;在这种情况下,这也可以很好地工作。)您也可以进行显式刷新:

    flush $cid
    

    这将追溯到puts

    关键问题2

    最佳实践将使用更像这样的服务器脚本,其中一个过程用于设置已接受套接字连接的服务,另一个过程用于处理消息的读取和写入。接受过程(server)关闭阻塞(并且通常也会调整缓冲),操作过程(readLine)使用eoffblocked来计算{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之上累积行,直到它有一个完整的命令(appendinfo complete帮助),或者你需要一些其他机制来处理数据传输。在生产代码中,委托像comm ...

    这样的包更容易