TCP/IP Client Service

Hi all,

I have a machine which provides a TCP/IP server that upon each client connection, sends a large set of segments that reflect a complete copy of the current state of the system (initial download) before streaming each event that occurs from there.

If I open up a cmd and enter: Telnet <IP address> <Port>[ENTER] it behaves as described above.

I then tried something like this on button press within a vision client:

from telnetlib import Telnet
HOST = <IP address>
PORT = <Port>
tn = Telnet(HOST, PORT)
OUTPUT = tn.read_all()
tn.close()
event.source.parent.getComponent('Text Area').text = OUTPUT

But since there is no EOF, this just gets hung at OUTPUT = tn.read_all() so I changed it to OUTPUT = tn.read_until("DC") # DC = Download complete and now after pressing the button and waiting about 3 seconds, my text area component displays all the information about the current state of the machine (about 10000 lines of data) before ending.

I would like to create some sort of service that gets the current state, stores each row into a db (I can do this with the above code) and then continually listens for and logs each event from there into the db. I’m hoping this will allow me to query the state of any subsystem whenever I wish to as well as to act (trigger) on certain events.

Any advice on how to accomplish something like this? Can I do it with with Ignition or would it be better outside?

I would use a long-lived thread (see my discussions about system.util.getGlobals and system.util.persistent) to open a socket for that purpose. If later events would replace earlier, I’d probably use a hierarchy of memory tags to hold current values. Clients would bind to tags of interest.

Hi Phil, thanks for your reply. I am definitely in over my head in terms of how to get a ‘long-lived thread’ working, would you be able to step me through the process of say creating one to toggle a single boolean memory tag every 5 seconds? How do you turn the thread on? How do you turn it off? What happens if the system switches to backup gateway?

Something like this:

from java.lang import Thread
from java.util.concurrent import ConcurrentHashMap

g = system.util.persistent("long-lived-thread")
# The .setdefault method will not replace an existing key, and
# is thread-safe (concurrent).
chm = g.setdefault('chm', ConcurrentHashMap())

tagpath = '[default]path/to/boolean/tag'

# Rely on closures/globals to make above available in the thread
def liveLongAndProsper():
	me = Thread.currentThread()
	# A ConcurrentHashMap's .put() method has the handy behavior of
	# atomically replacing and **returning** the previous value for
	# the given key.
	priorThread = chm.put('running', me)

	# If something was already running, interrupt it and join it.
	if priorThread:
		priorThread.interrupt()
		priorThread.join()

	# Not quite an infinite loop
	while not Thread.interrupted():
		v = system.tag.read(tagpath).value
		system.tag.writeSynchronous(tagpath, not v)
		# Sleep is only appropriate in a dedicated thread like this one
		Thread.sleep(5000)

system.util.invokeAsynchronous(liveLongAndProsper)

So this turns on when anything references its script module. And lives “forever”, or a successor kills it. You can turn it off with this:

priorThread = someScriptModule.chm.get('running')
if priorThread:
	priorThread.interrupt()

It won’t start on an inactive gateway, but won’t die. You’ll want the loop to check the gateway redundancy status if that’s important.

3 Likes

Thanks for the example Phil, I will see what I can come up with - something like calling the long running thread that will create a TCP/IP socket, connect it to the server, then loop through each ‘event’ (each event end’s with a ‘\r\n’ so I would read each character one by one, building the string until I detect the end, parse it out then write to a relevant memory tag as you have suggested).

There would be a large amount of memory tags for this (~10,000 at a guess) so I may even build into the script, the creation of the tags (if they don’t exist).

1 Like

Hi @pturmel,

As mentioned in the other thread, I am having trouble with python sockets on a tag event script which I am trying to use to get the long running thread started (and to stop it).

I have not done anything with java within Ignition before, would you be able to provide me with an example?

This is some of the python script I am trying to translate to java:

import socket
import sys

paths = ["[default]Client/State", "[default]Client/Command"]
values = system.tag.readBlocking(paths)
state = values[0].value
command = values[1].value
if command == 1 and state == 0:
	values = [1, 0]
	system.tag.writeBlocking(paths, values)
	try:
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		server_address = ('MACHINE', 53005)
		sock.connect(server_address)
		index = 1
		while True:
			char = ''
			row = ''
			while True:
				char = sock.recv(1)
				if char == '\r':
					char = sock.recv(1) #'\n'
					break
				else:
					row += char
			print row