Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 使用TCL插座时的挂窗_Sockets_Tcl_Tk - Fatal编程技术网

Sockets 使用TCL插座时的挂窗

Sockets 使用TCL插座时的挂窗,sockets,tcl,tk,Sockets,Tcl,Tk,我正在使用tclsocket命令在两个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

我正在使用tclsocket命令在两个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都提供不同的功能来处理需要同时提供的相同数据。

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

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

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

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

    关键问题1 处理客户重大问题的最佳方法是使用

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

    flush $cid
    
    这将在
    放置之后进行

    关键问题2 最佳实践将使用更像这样的服务器脚本,一个过程用于设置接受的套接字连接的服务,另一个过程用于处理消息的读写。accept过程(
    server
    )关闭阻塞(并经常调整缓冲),操作过程(
    readLine
    )使用
    eof
    fblocked
    计算
    是成功还是失败

    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之类的包变得更容易。

    是的,有一种方法;事实上,有几种方法。您必须提供更多关于B正在做什么的信息,以便我们能够提供帮助。如果您以前从未编写过异步程序,那么您将不得不学习:从一开始就可能会让您的大脑弯曲。@DonalFellows我已经添加了更多关于我要做什么的信息。如果你还需要什么,请告诉我。在此期间,我将尝试深入研究异步程序。Donal在尝试了更多的东西后,我发现当我对客户端和服务器都使用wish时,它们可以独立工作。看起来问题出在我和wish一起使用的程序上。我不知道怎么才能找到问题。此外,服务器仍然工作正常,我可以恢复命令输出。只有GUI没有响应。我自己在服务器上的小愿望小部件似乎工作正常。谢谢你的帮助。Donal,在这种情况下,使用open运行程序似乎很有效。我能够向程序发送命令,并在程序B在后台运行时返回结果。这是一个正确的方法吗?看看tcllib comm包,特别是异步部分,它可能会做你想要的。谢谢你详细的回答,多纳尔。我将合并您建议的更改。要添加此更改,您需要告诉Tcl使用“vwait-forever”Tcl命令“挂起”。它正是这样做的——永远地等待,或者用简单的英语说,看起来像是在等待。您需要包含某种代码,以便在服务器完成后正常关闭。如果只处理一个请求,然后关闭,请在“close$cid”之后添加一个“exit”,它将退出程序并返回操作系统。