1

我正在尝试在从解释器中运行 tclhttpd,但稍作修改以便在 tclkit 中运行。下面的代码“运行”(我可以点击http://localhost:8015)但从未到达底部的 puts 行,因为“服务器没有返回,它进入 [vwait forever]”。但是当我尝试“after 0 技巧”时,例如在“$httpd eval $cmd”行前面加上“after 0”,服务器根本没有运行,所以我认为“错误必须由 bgerror 处理”

但是我找不到如何使用 bgerror 的好例子,而且我的研究表明现在的惯例是使用“interp bgerror”。请参阅http://www2.tcl.tk/_/gsearch?S=bgerror返回的前几个示例;第一个链接包含“填写有用的技巧和使用 bgerror 的示例”这样的措辞,但是没有我可以辨别如何应用的示例,第二个链接的结论是“我对应该如何使用它的示例感兴趣”。

package require starkit
starkit::startup

set httpd_args [list]
set httpd [interp create]
$httpd eval "set argc [llength $httpd_args]"
set cmdargv "set argv [list $httpd_args ]"
$httpd eval "set topdir $starkit::topdir"
$httpd eval $cmdargv

set cmd [list source [file join $starkit::topdir bin/httpd.tcl]]
$httpd eval $cmd

puts "if seeing this controlled has returned"
4

3 回答 3

2

根据OP的评论完全编辑...

after 0 技巧是以下行:

after 0 $httpd eval $cmd

这样做是告诉 interp 将有问题的命令 ($http eval $cmd) 添加到事件队列中,这意味着它会在事件循环启动后运行(或者如果它已经启动则返回)。您可以在该页面的以下评论中看到对事件循环的依赖(由 Jacob Levy 撰写):

我应该注意,这取决于事件循环是否处于活动状态。

我的猜测是你正在运行一个普通的 Tclsh,这意味着你永远不会进入事件循环(Wish shell 在脚本末尾进入事件循环,Tcl shell 没有)。进入事件循环的标准方法是在 Tcl 代码结束后运行以下命令:

# Enter the event loop and stay in it until someone 
# sets the "forever" variable to something
vwait forever

话虽如此,在退出事件循环之前,您在 vwait 之后拥有的任何东西都不会运行。如果您希望 httpd 与您的代码并行运行,您需要:

  • 使用多个线程,或者写你的......这真的不是那么难
  • 代码是基于事件的......这要求您对基于编程的编程有足够的了解,以防止代码片段被缺乏执行时间。

希望有帮助。

于 2009-09-14T16:44:15.267 回答
1

如果我正确理解了您想要做什么,您的代码应该类似于:

set httpd_id [thread::create -preserved]
thread::send $http_id "source [file join $starkit::topdir bin/httpd.tcl]"

这样你就可以让 TclHttpd 在一个线程中运行,而不用担心 vwait 问题

如果您还想在 httpd 执行期间被告知任何错误,TclHttp 会将所有错误发送到日志文件。您可以配置日志的路径:

Log_SetFile "/logs/httpd_log"

你需要有 httpd::log 包。

我希望这有帮助。

于 2009-09-23T21:41:38.950 回答
1

我不太明白你问的问题。听起来您的目标是在一个解释器中启动一个 http 服务器,但以某种方式与主解释器进行交互。是对的吗?如果是这样,那与 bgerror 有什么关系?

您是否知道即使您在单独的解释器中运行服务器,它也没有在单独的线程中运行?也就是说,当任一解释器被 vwait 阻塞时,您不能 (*) 与主解释器交互。

(*) 你可以,如果你的交互采用 Tk 小部件的形式,它也利用了事件循环

至于如何使用 bgerror,它有几种工作方式。默认机制调用函数“bgerror”,你可以定义它来做任何你想做的事情。它需要一个字符串(错误消息的文本)并用它做一些事情。这可能是将错误打印到标准输出,显示它在对话框中,将其写入文件等。

例如,考虑这个交互式会话:

% proc bgerror {s} {puts "hey! I caught an error: $s"}
% # after 30 seconds, throw an error
% after 30000 {error "this is an error"}
after#0
% # after 40 seconds, terminate the event loop
% after 40000 {set ::done 1}
after#1
% # start the event loop
% vwait ::done
hey! I caught an error: this is an error
% # this prompt appears after 40 seconds or so

您还可以注册自己的错误处理程序,如“interp bgerror”文档中所述。这出现在 tcl 8.5 中,尽管它有一个直到 8.5.3 才修复的错误。

例如:

% set foo [interp create]
interp0
% $foo eval {proc myErrorHandler {args} {puts "myErrorHandler: $args"}}
% $foo bgerror myErrorHandler
myErrorHandler
% # after 30 seconds, throw an error
% $foo eval {after 30000 {error "this is an error"}}
after#0
% # after 40 seconds, terminate the loop
% $foo eval {after 40000 {set ::done 1}}
after#1
% $foo eval {vwait ::done}
myErrorHandler: {this is an error} {-code 1 -level 0 -errorcode NONE -errorinfo {this is an error
    while executing
"error "this is an error""
    ("after" script)} -errorline 1}
% # this prompt appears after 40 seconds or so

这有助于回答您的问题吗?

于 2009-09-24T18:37:04.057 回答