2

我正在使用 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

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

4

1 回答 1

2

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

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

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

此外,您还有一个小问题,如果您想发送多行数据,您会发现您的协议不合适。您可能关心也可能不关心这个问题,并且有几种不同的方法可以解决它。

关键问题1

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

fconfigure $cid -buffering none

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

flush $cid

那将在puts.

关键问题2

最佳实践将使用更像这样的服务器脚本,其中一个过程设置接受的套接字连接的服务,另一个过程处理消息的读取和写入。接受过程 ( server) 关闭阻塞(并且通常也调整缓冲)并且操作过程 ( readLine) 使用eofandfblocked来确定是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 这样的包变得更容易......</p>

于 2013-01-06T23:05:57.600 回答