我试图 在从属解释器中运行 tclhttpd 但稍加修改以便在 tclkit 中运行。下面的代码“运行”(我可以点击 http://本地主机:8015)但永远不会到达底部的 put 行,因为“服务器没有返回,它进入 [vwait Forever]”。但是当我尝试“0后技巧”时,例如将“after 0”添加到“$httpd eval $cmd”行之前,服务器根本不运行,所以我认为“错误必须由 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"
有帮助吗?

解决方案

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

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

(*)您可以,如果您的互动采用Tk小部件的形式,也可以利用事件循环

至于如何使用bgerror,它有两种方法可行。默认机制调用函数'bgerror'。你可以定义做任何你想做的事情。它需要一个字符串(错误消息的文本)并对其执行某些操作。 某些可能是将错误打印到stdout,在对话框中显示,将其写入文件等等。

作为示例,请考虑此交互式会话:

% 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中出现的,尽管它有一个 bug 直到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

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

其他提示

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

0 之后的技巧如下:

after 0 $httpd eval $cmd

它的作用是告诉解释器将相关命令($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 与您的代码并行运行,您需要:

  • 使用多个线程,或者编写您的...这真的没那么难
  • 基于事件的代码...这要求您充分理解基于基础的编程,以防止代码片段缺乏执行时间。

希望有帮助。

如果我已经正确理解了您的想法,那么您的代码应该类似于:

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包。

我希望这会有所帮助。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top