Updated 2015-09-02 21:27:06 by pooryorick

by Theo Verelst

This bwise page precedes more general work on the idea of using bwise in a distributed way, which can basically go three ways:

  • cooperating multiple (distributed) bwise-es, for instance working on the same design in a distributed fashion
  • linked into one distrbuted bwises for one application, where each bwise, probably on a different machine, or with windows on different X servers (or window terminals clients)
  • controlling a application with one (or a few non-distributed) bwise window, consisting of various, possibly distributed, processes.

This page is about the second option, to begin with.

We make two bwises connect up, and take part in a chain of events, linked to blocks on both its' canvasses which extends from the one to the other.

I was able to use two machines in this setup, a linux machine running tcl/tk 8.4, and a windows XP running PC having the latest cygwin suite on it, and my self compiled unix-type wish8.4 which uses Xwindows (for instance on the cygwin supplied XFree86 running fine under XP, albeit a touch slow in certain ways, it starts either the 'normal' way using the startx script, or by itself using xwin (manual page XWin), then twm or as I do wmaker, and some xterms), while running on XP.

Since that unix-type tcl/tk runs fine under XP with Xwindows output, I direct its windows where it is confortable, for instance another X screen on the other machine, and make it run bwise, along with another bwise, running on linux. That makes two bwises appear on the same machine, while they run not on the same machine, but they can't talk together yet, unless we'd use the X server based send command, but that's not the target, this setup should interconnect bwises (or other programs) running on all machine kinds, as long as they run a fairly basic version of tcl/tk and have sockets.

The setup is more or less symmetrical, but I use an example where the one machine has a terminal like block, and sets up a server socket, while the other simply feeds the data to some blocks and returns the result, and actively connects.
# This goes in the server side Bwise, after having loaded bwise
# -------------------------------------------------------------
global bcount scopeindex wireindex shellindex drumindex entrycount moncount proccount seqcount stackcount termindex textcount
set bcount 0
set scopeindex 0
set wireindex 4
set shellindex 0
set drumindex 0
set termindex 2
.mw.c create rectangle 82.0 124.0 122.0 154.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {from newblock block} -width 1.0
.mw.c create text 102.0 154.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {from crb label} -text from -width 0
.mw.c create text 123.0 143.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {from crb pinname data} -text data -width 0
.mw.c create line 142.0 144.0 122.0 144.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {from newblock pin data typeout} -width 2.0
.mw.c create rectangle 501.0 124.0 541.0 154.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {to newblock block} -width 1.0
.mw.c create text 521.0 154.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {to crb label} -text to -width 0
.mw.c create text 500.0 143.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {to crb pinname in} -text in -width 0
.mw.c create line 481.0 144.0 501.0 144.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {to  newblock pin in typein} -width 2.0
#
# I replaced the standard bwise saved canvas data for the 'term'inal block (which is 
# incomplete, still, te widgets don't get saved, with the new* call:
newterm term1 {} 219.0 124.0
#
.mw.c create line 142.0 144.0 199.0 144.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire2 connect wire from data term1 in} -width 1.0
.mw.c create line 481.0 144.0 439.0 144.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire3  connect wire to in term1 out} -width 1.0
#
# now the block related variables\n
set from.bfunc {puts "from received: ${from.data}"}
set from.bfunc_init {}
set from.data {}
set to.bfunc {puts $bwcons ${to.in} ; flush $bwcons}
set to.bfunc_init {}
set to.in {test 4}
set term1.bfunc {.mw.c.term1.t insert end  ${term1.in} tnavy; .mw.c.term1.t see end; .mw.c.term1.e selection range 0 end}
set term1.bfunc_init {.mw.c.term1.t del 0.0 end}
set term1.in {}
set term1.out {test 4}
set term1.trig {}
#
# The server procedure:
proc bwcon { {s} {ip} {po} } {
   global bwcons
   set bwcons $s
   fileevent $bwcons readable {
      set from.data [gets $bwcons]
#      net_funpropc from
# we don't do this because it closes the loop, see below
   }
   puts "Bwise connected to $ip:$po (socket: $s)"
   set bwcons $s
}

# And finally, open the server socket, at random (high) port
set s [socket -server bwcon 7011]

Now the second bwise's graph and setup of socket
# This is the client, or 'other side' code, which also gets loaded in a running bwise
# -----------------------------------------------------------------------------------
global bcount scopeindex wireindex shellindex drumindex entrycount moncount proccount seqcount stackcount termindex textcount
set bcount 0
set scopeindex 0
set wireindex 2
set shellindex 0
set drumindex 0
set entrycount 1
set proccount 1
.mw.c create rectangle 144.0 105.0 184.0 135.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {from newblock block} -width 1.0
.mw.c create text 164.0 135.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {from crb label} -text from -width 0
.mw.c create text 185.0 124.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {from crb pinname data} -text data -width 0
.mw.c create line 204.0 125.0 184.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {from newblock pin data typeout} -width 2.0
.mw.c create rectangle 427.0 105.0 467.0 135.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {to newblock block} -width 1.0
.mw.c create text 447.0 135.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {to crb label} -text to -width 0
.mw.c create text 426.0 124.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {to crb pinname in} -text in -width 0
.mw.c create line 407.0 125.0 427.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {to newblock pin in typein} -width 2.0
.mw.c create rectangle 288.0 105.0 328.0 135.0 -activedash {} -activefill {} -activeoutline {} -activeoutlinestipple {} -activestipple {} -activewidth 0.0 -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledoutline {} -disabledoutlinestipple {} -disabledstipple {} -disabledwidth 0 -fill yellow -offset 0,0 -outline darkblue -outlineoffset 0,0 -outlinestipple {} -state {} -stipple {} -tags {Proc1 newblock block} -width 1.0
.mw.c create text 308.0 135.0 -activefill {} -activestipple {} -anchor n -disabledfill {} -disabledstipple {} -fill darkblue -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {Proc1 crb label} -text Proc1 -width 0
.mw.c create text 287.0 124.0 -activefill {} -activestipple {} -anchor se -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {Proc1 crb pinname in} -text in -width 0
.mw.c create line 268.0 125.0 288.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {Proc1 newblock pin in typein} -width 2.0
.mw.c create text 329.0 124.0 -activefill {} -activestipple {} -anchor sw -disabledfill {} -disabledstipple {} -fill black -font {Helvetica -12} -justify left -offset 0,0 -state {} -stipple {} -tags {Proc1 crb pinname out} -text out -width 0
.mw.c create line 348.0 125.0 328.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {Proc1 newblock pin out typeout} -width 2.0
.mw.c create line 204.0 125.0 268.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire0 connect wire from data Proc1 in} -width 1.0
.mw.c create line 407.0 125.0 348.0 125.0 -activedash {} -activefill {} -activestipple {} -activewidth 0.0 -arrow none -arrowshape {8 10 3} -capstyle butt -fill darkblue -dash {} -dashoffset 0 -disableddash {} -disabledfill {} -disabledstipple {} -disabledwidth 0.0 -joinstyle round -offset 0,0 -smooth 0 -splinesteps 12 -state {} -stipple {} -tags {wire1 connect wire to in Proc1 out} -width 1.0
#
# now the block related variables\n
set from.bfunc {}
set from.bfunc_init {}
set from.data {test}
set to.bfunc {puts $bwcons ${to.in} ; flush $bwcons }
set to.bfunc_init {}
set to.in {test}
set Proc1.bfunc { set Proc1.out ${Proc1.in} }
set Proc1.bfunc_init {}
set Proc1.in {test}
set Proc1.out {test}
#
# Thus far standars bwise saved canvas based code
# Now open the socket to the server, fill in another host when you want:
set bwcons [socket localhost 7011]
#
# and make its read activity linked with the 'from' block:
fileevent $bwcons readable {set from.data [gets $bwcons] ; net_funprop from}

Now the bwises are connected, not that the server address just above is set to the same (local) host, which in my setup isn't the case, change to the machinename or IP address of the server bwise.

Now when we turn to the server bwise, and type something in the bottom line of the 'term'(-inal) block, and press return, the data will pass to the to block, which pushes it through the socket connection, triggers a readable event in the 'from' block on the other side, which makes it start a (local to the client) net_funprop function (similar to the bottom block popup menu entry), which transfers the data to proc1, and then (unchanged, until we put something more interesting in here) to the 'to' proc, which pushes it back into the socket stream connection, and triggers the 'from' block on the left of the server bwise.

Here the above example stops, but as is indicated in the code, we could set of a net_funprop here, too, and close the loop. Data then also is shown in the upper window of the terminal, the history, and is transered again to the 'to' block in the server bwise, which is triggered (its eval function called), and clearly we are in a loop.

The loop in my case was running at about 40 cycles per second including the graphical feedback to the both (one remote) bwise windows, which is at least not bad.

When the net_funprop is also in the server 'from' block, the history will accumulate the data you supplied in the command line of the terminal block (the bottom entry), for instance if there is one letter there, the letter starts getting repeated above, simply wipe the entry field clean, and the history will accumulate no more characters.

But, the loop has been triggered, and will continue, except no symbols are transfered...

The above image shows some development steps, and maybe some aid for issues arising from scripts. I didn't test them by pasting them from the wiki yet.

A classic issue: I tried replacing the client 'proc1' block with a block which executes shel commands (see also another of the above listed pages), expecting more than one line of response on a row, for instance when issueing a ls command.

Because the transfer network command in the server contains a tcl 'update' command, the fileevent handler is broken up, and as it seems called recursively, at the moment the update command is issues, which makes the network transfer mechanism lag behind the content of the 'from.data' pin, and basically give a list of one and the same line back in the terminal, instead of all the reply lines. Doing the transfer 'by hand', and also the invokation of the 'terminal' block function (like a method to insert the data on its input pin at the end of the history window and update the view to see the last line), thus getting rid of the update tcl command, makes all run.

I guess I should disable the handler and reenable it again at the end, but I wouldn't know now whether its possible to make it respond right, which is without recursion, I guess so. That is a matter of practicality, the sender mustn't continue sending data when the receiver can't keep up, and I want to be in control of extensive buffering, which isn't the case when all incoming data is effectively processed beyond my handlers idea..

I should test, and many delve into the manual a bit, whether indeed nested handlers are executed, I assumed first they would act atomically, now I assume that was the error...