基于线程的网络服务器

问题描述 投票:0回答:1

我已经设置了一个简单的 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"
multithreading webserver tcl
1个回答
0
投票

您可能还应该记录从工作线程中的套接字读取的第一行。对于 HTTP,它会特别告诉您动词和资源名称,并且可能会告诉您这些错误是大问题还是小错误。

该错误是由另一方提前关闭套接字引起的(如果没有动词和资源,why很难诊断)。这里可能应该将其视为非错误情况;问题的正确解决方案是也关闭这一端的套接字。

try {
   puts $chan ...
   puts $chan ...
} trap {POSIX EPIPE} {} {
   # Empty body; we just throw this error away
} finally {
   close $chan
}
© www.soinside.com 2019 - 2024. All rights reserved.