一个多线程的echo服务器

时间:2016-04-17 14:54:40

标签: multithreading sockets server tcl echo

此错误涉及哪个“线程”?

thufir@tleilax:~/wunderground$ 
thufir@tleilax:~/wunderground$ tclsh 21.12.tcl
can't read "thread": no such variable
    while executing
"thread::send -async $thread {
thread::attach $sock
fconfigure $sock -buffering line -blocking 0
fileevent $sock readable [list ReadLine $sock]
SendMes..."
    (file "21.12.tcl" line 71)
thufir@tleilax:~/wunderground$ 

示例代码21-12:

package require Tcl 8.4
package require Thread 2.5


set sock 12345
set host 127.0.0.1
#set port 7777

if {$argc > 0} {
    set port [lindex $argv 0]
} else {
    set port 9001
}

socket -server _ClientConnect $port
proc _ClientConnect {sock host port} {
}

#Tcl holds a reference to the client socket during
#this callback, so we can't transfer the channel to our
#worker thread immediately. Instead, we'll schedule an
#after event to create the worker thread and transfer
#the channel once we've re-entered the event loop.
after 0 [list ClientConnect $sock $host $port]
proc ClientConnect {sock host port} {
    #Create a separate thread to manage this client. The
    #thread initialization script defines all of the client
    #communication procedures and puts the thread in its
    #event loop.
    set thread [thread::create {
        proc ReadLine {sock} {
            if {[catch {gets $sock line} len] || [eof $sock]} {
                catch {close $sock}
                thread::release
            } elseif {$len >= 0} {
                EchoLine $sock $line
            }
        }
        proc EchoLine {sock line} {
            if {[string equal -nocase $line quit]} {
                SendMessage $sock \
                    "Closing connection to Echo server"
                catch {close $sock}
                thread::release
            } else {
                SendMessage $sock $line
            }
        }
        proc SendMessage {sock msg} {
            if {[catch {puts $sock $msg} error]} {
                puts stderr "Error writing to socket: $error"
                catch {close $sock}
                thread::release
            }
        }
        # Enter the event loop
        thread::wait
    }]


    #Release the channel from the main thread. We use
    #thread::detach/thread::attach in this case to prevent
    #blocking thread::transfer and synchronous thread::send
    #commands from blocking our listening socket thread.
    # Copy the value of the socket ID into the
    # client's thread
    thread::send -async $thread [list set sock $sock]
    # Attach the communication socket to the client-servicing
    # thread, and finish the socket setup.
}
thread::send -async $thread {
    thread::attach $sock
    fconfigure $sock -buffering line -blocking 0
    fileevent $sock readable [list ReadLine $sock]
    SendMessage $sock "Connected to Echo server"
}
vwait forever

来自:

本章来自Tcl和Tk的实用编程,第4版。 版权所有2003©Brent Welch,Ken​​ Jones http://www.beedub.com/book/

我不得不添加sockhost变量,这让我觉得我错过了更多。线程变量的名称“thread”似乎有问题(?)。

2 个答案:

答案 0 :(得分:1)

你已经设法咀嚼书中线条的顺序,足以使代码真的不起作用。如果我们查看relevant chapter,我们会看到代码实际就是这样说的:

proc _ClientConnect {sock host port} {

    # Tcl holds a reference to the client socket during
    # this callback, so we can't transfer the channel to our
    # worker thread immediately. Instead, we'll schedule an
    # after event to create the worker thread and transfer
    # the channel once we've re-entered the event loop.

    after 0 [list ClientConnect $sock $host $port]
}

那个很多不那么奇怪了!同样,您已移动此块:

thread::send -async $thread {
    thread::attach $sock
    fconfigure $sock -buffering line -blocking 0
    fileevent $sock readable [list ReadLine $sock]
    SendMessage $sock "Connected to Echo server"
}
ClientConnect程序之外的

,尽管它需要在那里运行,因为那里定义了thread变量。 (这就是你收到错误信息的原因,顺便说一句。)如果你解决了这些问题(并检查你是否也以同样的方式做了其他愚蠢的错误),那么代码应该可行。

如果您要从其他地方复制示例,请正确复制它们。随机更改运行代码片段的上下文可能无法在任何编程语言中正常运行

答案 1 :(得分:0)

至少从这个PDF中复制/粘贴有些奇怪的事情,它实际上是以错误的顺序排列。我通过在线PDF到文本转换器运行它,结果相同。

要遵循的非常缩进的代码(没有评论,不能很好地复制):

package require Tcl 8.4
package require Thread 2.5
if {$argc > 0} {
set port [lindex $argv 0]
} else {
set port 9001
}



socket -server _ClientConnect $port

proc _ClientConnect {sock host port} {

after 0 [list ClientConnect $sock $host $port]

}






proc ClientConnect {sock host port} {

set thread [thread::create {
proc ReadLine {sock} {
if {[catch {gets $sock line} len] || [eof $sock]} {
catch {close $sock}
thread::release
} elseif {$len >= 0} {
EchoLine $sock $line
}
}


proc EchoLine {sock line} {
if {[string equal -nocase $line quit]} {
SendMessage $sock \
"Closing connection to Echo server"
catch {close $sock}
thread::release
} else {
SendMessage $sock $line
}
}

proc SendMessage {sock msg} {
if {[catch {puts $sock $msg} error]} {
puts stderr "Error writing to socket: $error"
catch {close $sock}
thread::release
}
}


thread::wait
}]




thread::detach $sock


thread::send -async $thread [list set sock $sock]


thread::send -async $thread {
thread::attach $sock
fconfigure $sock -buffering line -blocking 0
fileevent $sock readable [list ReadLine $sock]
SendMessage $sock "Connected to Echo server"
}

}


vwait forever

太糟糕的komodo不会自动缩进。无论如何,它似乎至少运行没有错误。研究naglfar功能。