Tcl IO通道问题:关闭stdout后puts为何无法默认输出到socket通道
问题原因解析
首先纠正一个认知误区:Tcl 的 puts 命令在不指定通道参数时,只会固定查找名为 stdout 的默认输出通道,不会自动选择最近打开的可写通道(不管是文件通道还是socket通道都不例外)。
你之前关闭 stdout 后写入文件通道能生效,本质是你参考的重定向教程里隐含了通道重命名的操作,你把打开的文件通道重命名为了stdout,才会让puts默认写入文件,并不是关闭stdout后系统自动选了新的文件通道。如果没有重命名操作,哪怕是文件场景,关闭stdout后调用puts一样会报can not find channel named "stdout"的错误。
而你的socket代码无法生效,还有第二个专属问题:socket -server $port返回的是监听套接字,仅用于监听客户端连接请求,本身不是可写入数据的IO通道,根本不能用来做输出目标。只有客户端接入后触发accept回调返回的连接套接字,才是可读写的有效数据通道。
正确实现方案
如果要让无通道参数的puts默认写入socket通道,需要完成两个操作:
- 拿到有效可写的socket连接通道(客户端直接连接返回的通道,或者服务端accept回调拿到的连接通道)
- 关闭原有
stdout后,把目标socket通道重命名为stdout
客户端场景示例
# 连接到目标服务端,拿到可写的连接通道 set sock [socket 127.0.0.1 8888] # 关闭默认stdout后重命名通道 close stdout chan rename $sock stdout # 此时puts会直接输出到socket连接中 puts "hello there" flush stdout
服务端场景示例
# 客户端接入回调,参数sock就是可写的连接通道 proc accept {sock addr port} { close stdout chan rename $sock stdout # 内容会直接发送给已连接的客户端 puts "hello there" flush stdout } # 启动服务端监听,返回的是不可写的监听套接字 socket -server accept 8888 # 进入事件循环等待客户端连接 vwait forever
内容的提问来源于stack exchange,提问作者almostacoder
相关产品推荐
相关产品推荐

