The application I am trying to build is as follows.
Java Client <---> TCL server (say Server.tcl) <---> Some other TCL script (say ABC.tcl)
I am using Socket programming for the communication between Java Client and TCL server. Now my requirement is to call ABC.tcl from Server.tcl at runtime. ABC.tcl while executing will send some questions to Java client through server.tcl. The user sitting at Java client should send the reply to the questions asked and the answer should come back to ABC.tcl. Now while the reply comes back the ABC.tcl should wait. But I can't have a busy waiting loop in ABC.tcl as the control will not come to Server.tcl as it is the once who will talk to the Java client.
ABC.tcl will be using some procedures defined in Server.tcl. The design can be changed though if required.
I was thinking of using Threads in TCL. I was planning to call ABC.tcl as a separate thread, and then keep it waiting for the replies. This way the Server.tcl can execute separately from ABC.tcl.
Wanted opinion on is their any better way to do it ? If Threads is the only better way, what are the challenges I might encounter and how can I take care of them ?
Edited :
I am not using socket communication between Server.tcl and ABC.tcl. In Server.tcl, I am sourcing ABC.tcl and when some communication request comes from the Java client, I am calling a procedure (say proc someProc{}) of ABC.tcl. Now in someProc procedure, some processing is done and a question (say "Do you want to continue ?") is sent back to Java client through Server.tcl. Now in ABC.tcl I want the procedure someProc to wait till the user enters something. And when the user enters the answer (either yes/no), I want the procedure to continue execution from the point where it was waiting for user input.
Now what is happening is I am not able to correctly set that waiting condition as required. I tried using a flag variable that will be updated when the user inputs the answer, and tried keeping a busy waiting loop in someProc, based on the flag variable. but for when user input comes, it does not resume execution from waiting loop onwards. It starts like normal request and goes into the procedure that is registered in Server.tcl to handle the incoming data.
I have the "vwait events" call and also I have " fileevent $sock readable [list svcHandler $sock]" in the Server.tcl.
I am not able to get, how exactly can I wait in the procedure someProc in the ABC.tcl and resume processing from same busy wait, based on user input.
Heading ##Server.tcl File :
source "<path>/serverTest.tcl"
set svcPort [lindex $argv 0]
set filePath <path where all related files are kept>
set replyReady 0
set packet ""
proc writeToFile {fileName data mode} {
set fileId [open $fileName $mode]
puts -nonewline $fileId $data
close $fileId
}
proc writeJavaUTF {sock msg} {
set date [exec date]
set msg $date$msg
set data [encoding convertto utf-8 $msg]
puts -nonewline $sock [binary format "S" [string length $data]]$data
}
proc readJavaUTF {sock} {
binary scan [read $sock 2] "S" len
set data [read $sock [expr {$len & 0xFFFF}]]
return [encoding convertfrom utf-8 $data]
}
proc sendMessageToUser {sock msg} {
writeToFile [exec pwd]/CTS/log "\nSending Message Back to Client" "a"
writeJavaUTF $sock $msg\n
}
proc setReplyReady {} {
global replyReady
set replyReady 1
writeToFile [exec pwd]/CTS/log "\nSetReplyReady" "a"
}
proc resetReplyReady {} {
global replyReady
set replyReady 0
writeToFile [exec pwd]/CTS/log "\nResetReplyReady" "a"
}
proc getReplyReadyStatus {} {
global replyReady
writeToFile [exec pwd]/CTS/log "\nReply Ready is : $replyReady" "a"
return $replyReady
}
proc executeCommand {sock msg} {
writeToFile [exec pwd]/CTS/log "\nexecuteCommand" "a"
runServerTest $sock
}
# Handles the input from the client and client shutdown
proc svcHandler {sock} {
global packet replyReady
set packet [readJavaUTF $sock] ;# get the client packet
writeToFile [exec pwd]/CTS/log "\nThe packet from the client is $packet" "w"
set packet [string range $packet 0 [expr {[string first "\n" $packet] - 1}]]
set endChar "EOC"
if {[eof $sock] || ![string compare -nocase $packet $endChar]} { ;# client gone or finished
writeToFile [exec pwd]/CTS/log "Closing the socket" "a"
writeToFile [exec pwd]/CTS/flag "0" "w"
close $sock ;# release the servers client channel
exit
} else {
#doService $sock $ipacket
set typeReply "reply"
set typeExecute "exec"
set type [string range $packet 0 [expr {[string first ":" $packet] - 1}]]
writeToFile [exec pwd]/CTS/log "\nThe type is : $type" "a"
# If it is not a reply for a request
if {![string compare -nocase $type $typeExecute]} {
executeCommand $sock $packet
} else {
writeToFile [exec pwd]/CTS/log "\nExecuting the ELSE" "a"
setReplyReady
}
}
}
proc accept {sock addr port} {
# Setup handler for future communication on client socket
fileevent $sock readable [list svcHandler $sock]
# Read client input in lines, disable blocking I/O
fconfigure $sock -buffering line -blocking 0 -translation binary
return $sock
}
set sock [socket -server accept $svcPort]
vwait events ;# handle events till variable events is set
Heading ## serverTest.tcl (As ABC.tcl)
proc runServerTest {sock} {
global replyReady
writeToFile [exec pwd]/CTS/log "\nInside serverTest.tcl." "a"
resetReplyReady
sendMessageToUser $sock "From Server : The socket is working. Do you want to continue ?"
writeToFile [exec pwd]/CTS/log "\nWaiting for user input" "a"
#Loop untill the reply is read from the socket
while {![getReplyReadyStatus]} {
after 1000
}
set retMessage [getPacket]
resetReplyReady
writeToFile [exec pwd]/CTS/log "\nThe reply from user is : $retMessage" "a"
}
Heading ## Challenge in the code
I send a new request as "exec:Hello" And I send reply as "reply:yes"
As you can see in the proc svcHandler{}, if it is a new request I execute the executeCommand{} proc. Else, I set the replyReady flag. When I execute the executeCommand{} proc, the proc runServerTest{} is called which is in serverTest.tcl. Now in this proc, I send the question back to the user, which I am able to see on the JAVA UI screen on client. And when I try to send the reply, the proc setReplyready{} which is in svcHandler{}, is not executed at all. When I saw the log file, I could see the output of the proc getReplyReadyStatus{}, which is being called from while loop in proc runServerTest{}, after every second. It means the while loop is executing indefinitely. And as the proc setReplyReady{} is not getting called from svcHandler{} may be the while loop is not exiting. Don't really know where the process is waiting. Any workaround ?
Thanks, Peeyush