2016-04-17 9 views
0

Auf welchen "Thread" bezieht sich dieser Fehler?Ein Multi-Thread-Echo-Server

[email protected]:~/wunderground$ 
[email protected]:~/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) 
[email protected]:~/wunderground$ 

Beispielcode 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 

aus:

Dieses Kapitel ist von Practical Programming in Tcl und Tk, 4. Ed. Copyright 2003 © Brent Welch, Ken Jones http://www.beedub.com/book/

Ich hatte die sock und und host Variablen hinzuzufügen, die mich denken lässt, dass ich mehr bin fehlt. Der Name "thread" für eine Thread-Variable erscheint fraglich (?).

+1

Nach einigen Formatierungen überrascht mich der Fehler nicht wirklich: http://paste.tclhelp.net/?id=i0f –

+0

Es scheint, dass der eingefügte Code den gleichen Fehler hat, Zeile 71? – Thufir

+0

Ja, aber ein Syntax-Checker ist nicht die schlechteste Idee. –

Antwort

1

Sie haben es geschafft, die Reihenfolge der Zeilen im Buch gerade so zu kauen, dass der Code wirklich nicht funktioniert. Wenn wir uns die relevant chapter betrachten, sehen wir, dass der Code tatsächlich sagt diese Dinge so:

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] 
} 

Das viel weniger seltsam! In ähnlicher Weise haben Sie diesen Block bewegt:

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" 
} 

außerhalb des ClientConnect Verfahren, obwohl es im Inneren gibt, um zu laufen, weil das ist, wo die thread Variable definiert ist. (Deshalb erhalten Sie diese Fehlermeldung, BTW.) Wenn Sie diese Dinge beheben (und überprüfen, ob Sie andere dumme Fehler in der gleichen Richtung gemacht haben), sollte der Code funktionieren.

Wenn Sie Beispiele von anderen kopieren möchten, kopieren Sie sie bitte korrekt. Das zufällige Ändern des Kontextes, in dem Codefragmente ausgeführt werden, funktioniert wahrscheinlich nicht gut in einer beliebigen Programmiersprache ...

+0

Fair genug, die Änderungen sind nur wegen Kopieren/Einfügen von PDF immer schroff. Ich werde wieder zurück gehen, weil ich wusste, dass das das Problem war. Weil ich Variablen deklarieren musste, von denen ich nicht glaube, dass sie richtig deklariert wurden, führte dies zu der Schlussfolgerung, dass der Beispielcode fehlerhaft war. Hatte keine Ahnung, dass es ein Kopier-/Einfügefehler war. – Thufir

0

Es ist etwas komisch über das Kopieren/Einfügen von mindestens dieser PDF, es bringt buchstäblich Zeilen in die falsche Reihenfolge. Ich führte es mit dem gleichen Ergebnis durch einen Online-PDF-Konverter.

Badly gegliederten Code zu folgen (ohne Kommentare, die auch nicht kopieren):

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 

Schade Komodo nicht automatisch Einzug. Jedenfalls scheint es zumindest ohne Fehler zu laufen. Ein Blick in die Fähigkeiten von Naglfar.