# TCP/IP Client Service

**URL:** <https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118>\
**Category:** Ignition\
**Created:** [January 18, 2022, 4:14pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118 "2022-01-18T16:14:47Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![dion.botha](https://avatars.discourse-cdn.com/v4/letter/d/46a35a/32.png) [@dion.botha](https://forum.inductiveautomation.com/u/dion.botha)\
**Post date:** [January 18, 2022, 4:14pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/1 "2022-01-18T16:14:47Z")

</div>

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:

```auto
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?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 18, 2022, 4:22pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/2 "2022-01-18T16:22:06Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![dion.botha](https://avatars.discourse-cdn.com/v4/letter/d/46a35a/32.png) [@dion.botha](https://forum.inductiveautomation.com/u/dion.botha)\
**Post date:** [January 19, 2022, 4:49pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/3 "2022-01-19T16:49:07Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [January 19, 2022, 5:58pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/4 "2022-01-19T17:58:13Z")

</div>

Something like this:

```auto
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:

```auto
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.

---

<div class="post-metadata">

**Author:** ![dion.botha](https://avatars.discourse-cdn.com/v4/letter/d/46a35a/32.png) [@dion.botha](https://forum.inductiveautomation.com/u/dion.botha)\
**Post date:** [January 20, 2022, 4:53pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/5 "2022-01-20T16:53:44Z")

</div>

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).

---

<div class="post-metadata">

**Author:** ![dion.botha](https://avatars.discourse-cdn.com/v4/letter/d/46a35a/32.png) [@dion.botha](https://forum.inductiveautomation.com/u/dion.botha)\
**Post date:** [January 26, 2022, 10:19pm UTC](https://forum.inductiveautomation.com/t/tcp-ip-client-service/55118/6 "2022-01-26T22:19:22Z")

</div>

Hi @pturmel,

As mentioned in the [other](https://forum.inductiveautomation.com/t/import-socket-error/29353/7) 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:

```auto
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

```
