我已经设置了一个简单的 tcl 服务器,可以在 https://elotor-tcl-http-server-demo.hf.space/
访问proc Server {startTime channel clientaddr clientport} {
puts "Connection from $clientaddr registered"
fconfigure $channel -buffering line
fileevent $channel readable [list Echo $channel $startTime]
}
proc Echo {sock startTime} {
if { [catch {gets $sock line}] || [eof $sock] } {
close $sock
return
}
set now [clock seconds]
set htmlContent "
<!DOCTYPE html>
<html>
<head><title>Test Page</title></head>
<body><h1>Hello World</h1>
[expr {$now - $startTime}] seconds since start.</br>$line</body>
</html>
"
puts $sock "HTTP/1.1 200 OK"
puts $sock "Content-Type: text/html"
puts $sock "Content-Length: [string length $htmlContent]"
puts $sock ""
puts $sock $htmlContent
puts $sock "EOF"
flush $sock
close $sock
}
socket -server [list Server [clock seconds]] -myaddr 0.0.0.0 7860
proc bgerror msg {
puts stderr "[clock format [clock seconds]] $msg\n$::errorInfo"
}
vwait forever
我正在考虑使用线程而不是事件,但我不知道这是否值得,也不知道如何去做。
我尝试了https://www.activestate.com/blog/concurreny-tcl-weaving-threads/
的方法package require Thread
proc NewConnection {startTime channel clientaddr clientport} {
puts "Connection from $clientaddr registered"
set t [thread::create {
proc HandleConnection {channel startTime} {
fconfigure $channel -buffering none
set data {}
while {![eof $channel]} {
if {[gets $channel line] < 0} {
continue
}
append data $line \n
}
set now [clock seconds]
set htmlContent "
<!DOCTYPE html>
<html>
<head><title>Test Page</title></head>
<body><h1>Hello World</h1>
[expr {$now - $startTime}] seconds since start.</br>$line</body>
</html>
"
puts $channel {HTTP/1.1 200 OK}
puts $channel {Content-Type: text/html}
puts $channel "Content-Length: [string length $htmlContent]"
puts $channel {}
puts $channel $htmlContent
puts $channel EOF
close $channel
thread::release
}
thread::wait
}]
thread::transfer $t $channel
thread::send -async $t [list HandleConnection $channel $startTime]
}
socket -server _Accept -myaddr 0.0.0.0 7860
proc _Accept {s ipaddr port} {
after idle [list NewConnection [clock seconds] $s $ipaddr $port]
}
proc bgerror msg {
puts stderr "[clock format [clock seconds]] $msg\n$::errorInfo"
}
vwait forever
但是我收到以下错误:
Connection from XX.XX.XX.XX registered
Error from thread tid0x7f2693dddb38
error writing "sock7f2693e25e00": broken pipe
while executing
"puts $channel {HTTP/1.1 200 OK}"
(procedure "HandleConnection" line 19)
invoked from within
"HandleConnection sock7f2693e25e00 1714214861"
Connection from XX.XX.XX.XX registered
Error from thread tid0x7f2693d46b38
error writing "sock7f2693e26080": broken pipe
while executing
"puts $channel {HTTP/1.1 200 OK}"
(procedure "HandleConnection" line 19)
invoked from within
"HandleConnection sock7f2693e26080 1714214862"
Connection from XX.XX.XX.XX registered
Error from thread tid0x7f2693c8fb38
error writing "sock7f2693e26380": broken pipe
while executing
"puts $channel {HTTP/1.1 200 OK}"
(procedure "HandleConnection" line 19)
invoked from within
"HandleConnection sock7f2693e26380 1714214863"
Connection from XX.XX.XX.XX registered
Error from thread tid0x7f2693b98b38
error writing "sock7f2693e26e20": broken pipe
while executing
"puts $channel {HTTP/1.1 200 OK}"
(procedure "HandleConnection" line 19)
invoked from within
"HandleConnection sock7f2693e26e20 1714214864"
您可能还应该记录从工作线程中的套接字读取的第一行。对于 HTTP,它会特别告诉您动词和资源名称,并且可能会告诉您这些错误是大问题还是小错误。
该错误是由另一方提前关闭套接字引起的(如果没有动词和资源,why很难诊断)。这里可能应该将其视为非错误情况;问题的正确解决方案是也关闭这一端的套接字。
try {
puts $chan ...
puts $chan ...
} trap {POSIX EPIPE} {} {
# Empty body; we just throw this error away
} finally {
close $chan
}