2

構築しようとしているアプリケーションは次のとおりです。

Java クライアント <---> TCL サーバー (Server.tcl など) <---> その他の TCL スクリプト (ABC.tcl など)

Java クライアントと TCL サーバー間の通信にソケット プログラミングを使用しています。今私の要件は、実行時に Server.tcl から ABC.tcl を呼び出すことです。実行中の ABC.tcl は、server.tcl を介して Java クライアントにいくつかの質問を送信します。Java クライアントに座っているユーザーは、尋ねられた質問に対する応答を送信する必要があり、その回答は ABC.tcl に返されます。応答が戻ってくるまで、ABC.tcl は待機する必要があります。しかし、私は ABC.tcl でビジーな待機ループを持つことはできません。これは、Java クライアントと対話するのは Server.tcl だけであるため、制御が Server.tcl に到達しないためです。

ABC.tcl は、Server.tcl で定義されたいくつかのプロシージャを使用します。ただし、必要に応じてデザインを変更することができます。

TCLでスレッドを使用することを考えていました。私は ABC.tcl を別のスレッドとして呼び出し、応答を待機することを計画していました。このようにして、Server.tcl は ABC.tcl とは別に実行できます。

それを行うためのより良い方法はありますか?スレッドが唯一の優れた方法である場合、どのような課題が発生する可能性があり、どのように対処すればよいでしょうか?

編集:

Server.tcl と ABC.tcl の間でソケット通信を使用していません。Server.tcl では、ABC.tcl をソースとしており、Java クライアントから何らかの通信要求が来ると、ABC.tcl のプロシージャ (proc someProc{} など) を呼び出しています。someProc プロシージャでは、何らかの処理が行われ、質問 (「続行しますか?」など) が Server.tcl を介して Java クライアントに返されます。ABC.tcl では、プロシージャ someProc がユーザーが何かを入力するまで待機するようにします。そして、ユーザーが答え (はい/いいえ) を入力すると、ユーザー入力を待っていた時点から手順を実行し続けたいと思います。

今起こっていることは、必要に応じてその待機条件を正しく設定できないことです。ユーザーが回答を入力したときに更新されるフラグ変数を使用してみました。フラグ変数に基づいて、someProc でビジーな待機ループを維持しようとしました。ただし、ユーザー入力が来ると、待機ループ以降の実行は再開されません。通常のリクエストのように開始され、受信データを処理するために Server.tcl に登録されているプロシージャに入ります。

「vwait イベント」呼び出しがあり、Server.tcl に「fileevent $sock readable [list svcHandler $sock]」もあります。

ユーザー入力に基づいて、ABC.tcl のプロシージャ someProc で待機し、同じビジー待機から処理を再開する方法を正確に取得できません。

見出し ##Server.tcl ファイル :

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

見出し ## serverTest.tcl (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"
}

見出し ## コード内の課題

「exec:Hello」として新しいリクエストを送信し、「reply:yes」として返信を送信します

svcHandler{} プロシージャでわかるように、それが新しいリクエストの場合は、executeCommand{} プロシージャを実行します。それ以外の場合は、replyReady フラグを設定します。executeCommand{} プロシージャを実行すると、serverTest.tcl にあるプロシージャ runServerTest{} が呼び出されます。この手順では、質問をユーザーに送り返します。これは、クライアントの Java UI 画面で確認できます。返信を送信しようとすると、svcHandler{} にある setReplyready{} プロシージャがまったく実行されません。ログ ファイルを見ると、1 秒ごとに proc runServerTest{} の while ループから呼び出されている proc getReplyReadyStatus{} の出力を確認できました。while ループが無期限に実行されていることを意味します。また、プロシージャ setReplyReady{} が svcHandler{} から呼び出されていないため、while ループが終了していない可能性があります。プロセスがどこで待っているのかよくわかりません。回避策はありますか?

ありがとう、ピーユッシュ

4

3 に答える 3

6

スレッドを使用しないでください。イベント ループを使用します。

読んでくださいfileeventhttp://www.tcl.tk/man/tcl8.6/TclCmd/fileevent.htm

一般に、Java クライアント ソケットと ABC スクリプト ソケットの両方のイベント ハンドラーを設定して、読み取り可能になったときにトリガーし、データが到着したときに必要な処理を実行します。

ウォッチドッグタイマーなどの時間指定操作を実装する必要がある場合は、afterコマンドを確認してください。

于 2013-05-14T07:51:32.653 に答える
3

サーバーとユーザーなど、非同期で通信したいものが複数ありますが、8.6 未満の Tcl バージョンでは、インタープリターごとに 1 つの実行ポイント (スタック フレーム) しか持つことができません。そのため、あるループでサーバー通信を待ち、別のループでユーザー通信を待つことはできません。それらの 1 つを、その仕事をして を返すハンドラーとして書き直すか、次を使用します。

  • Tcl 8.6 のコルーチン。
  • 複数の通訳者。
  • 複数のプロセス (独自の tclsh で ABC.tcl を開始します)。
  • 複数のスレッド。

接続ごとに 1 つのインタープリター/スレッド?

于 2013-05-14T13:04:58.583 に答える