1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 | ###############################################################################
# Copyright (c) 2005-2024 by Altair Engineering, Inc.
# All rights reserved.
#
# Altair Engineering, Inc. makes this software available as part of the Vision
# tool platform. As long as you are a licensee of the Vision tool platform
# you may make copies of the software and modify it to be used within the
# Vision tool platform, but you must include all of this notice on any copy.
# Redistribution without written permission to any third party, with or
# without modification, is not permitted.
# Altair Engineering, Inc. does not warrant that this software is error free
# or fit for any purpose. Altair Engineering, Inc. disclaims any liability for
# all claims, expenses, losses, damages and costs any user may incur as a
# result of using, copying or modifying the software.
# =============================================================================
# @userware
# Open Socket Connection
# @section
# Miscellaneous Userware Examples
# @description
# This Userware example script establishes a socket connection between
# *Vision PRO (server) and an arbitrary Tcl-based application, e.g.
# tclsh (client). This file contains the code for both sides, the server
# and the client side.
#
# Try it out: Source this file into a *Vision PRO tool AND into a
# standard "tclsh" and type commands at the tclsh prompt like
# ```
# set oid {inst gl85 C1 M2 U2 m10}
# set db [sv set db]
# set val [sv $db flatattr $oid getMergedValue w]
# ```
# or
# ```
# sveval $script
# ```
#
# The first executes `set db` and `$db flatattr $oid getMergedValue w`
# in the *Vision process and sets the result to the `val` variable,
# the second executes the contents of the `script` variable.
# @files
# oem/socket.tcl
# @tag
# zdb gui
###############################################################################
##
# Set this to an unused TCP/IP port at your machine.
#
set port 12345
if {[info commands zdb] == "zdb"} {
##
# This seems to be the *Vision process.
# Listen on TCP port for incoming connections.
#
if {![info exists serverSocket]} {
set serverSocket [socket -server gotConnection $port]
}
##
# gotConnection waits for commands, executes them and sends
# back the command result.
#
proc gotConnection {data ip clientPort} {
chan configure $data -blocking true -translation binary
set clientId "\[$ip:$clientPort\]"
gui console print "Got connected from $clientId"
#checker exclude warnStyleCodeBlock
#checker exclude warnStyleCodeBlockShort
chan event $data readable [list doCommand $data $clientId]
}
##
# doCommand assumes incoming data stream "len cmd", e.g.
# 5\nxxxxx
# and send outgoing data string "ret len msg", e.g.
# 0 3\nxxx
# 1 12\nxxxxxxxxxxxx
#
proc doCommand {data clientId} {
if {[gets $data cmdlen] > 0} {
if {![string is integer $cmdlen]} {
zmessage print ERR "protocol sync error with $clientId"
close $data
return
}
set cmd [read $data $cmdlen]
set ok [catch {uplevel #0 $cmd} ret]
puts $data "$ok [string bytelength $ret]"
puts -nonewline $data $ret
flush $data
} else {
close $data
}
}
} else {
##
# Here we assume to run on the client side in an ordinary tclsh
# Setup TCP connection.
#
set data [socket localhost $port]
chan configure $data -blocking true -translation binary
##
# procedure "sveval" sends the "script" to *Vision to be evaluated
# and reads the results and returns the result as if the script would
# have been executed in the local process.
#
proc sveval {script} {
global data
if {$data == ""} {
return -code error "no communication channel"
}
puts $data [string bytelength $script]
puts -nonewline $data $script
flush $data
if {([gets $data head] > 0) && ([scan $head "%d %d" ok len] == 2)} {
set msg [read $data $len]
return -code $ok $msg
} else {
close $data
set data ""
return -code error "protocol sync error"
}
}
##
# procedure "sv" sends all args to *Vision and returns the
# result as if the command would have been executed in the local process.
#
proc sv {args} {
return [sveval $args]
}
}
|