# Opening Sockets to TCP devices using scripting

**URL:** <https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860>\
**Category:** Ignition\
**Tags:** ignition81, scripting\
**Created:** [July 25, 2023, 1:03pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860 "2023-07-25T13:03:41Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hayden\_Watson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hayden_watson/32/48792_2.png) [@Hayden\_Watson](https://forum.inductiveautomation.com/u/Hayden_Watson)\
**Post date:** [July 25, 2023, 1:03pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/1 "2023-07-25T13:03:41Z")

</div>

Hey all,  
We've got some machines that will be sending and receiving data to our Ignition using python TCP APIs, and then ideally writing these to tags.

In a testing python prgram that was developed, a socket to the relevant port is opened and made as an object in the code. This socket is then used in an endless while loop to pull the data out in a continuous stream.

Is there a best practice to stream data over a socket like this in Ignition.

We have two options in my mind:

- Using Gateway Timer Event. Open a socket and request the data, then close that socket before the next Timer loop, or;
- Have a timer script with a very long timer delay, on a dedicated thread. And just use this endless while loop idea.

We're only pulling over 3/4 JSON objects of data in each cycle, so not massively heavy duty.

What are the risks and/or benefits in the two options.

---

<div class="post-metadata">

**Author:** ![kyler.kamyszek](https://avatars.discourse-cdn.com/v4/letter/k/a4c791/32.png) [@kyler.kamyszek](https://forum.inductiveautomation.com/u/kyler.kamyszek)\
**Post date:** [July 25, 2023, 2:16pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/2 "2023-07-25T14:16:12Z")

</div>

I'm using your first option with no issues. I also use a ping script on the options with an expression tag to detect if my devices are connected. My application uses devices that are on and off frequently. Although, I never listen for a response back with this method.

I also have a 3rd option, and that's using the TCP device driver in the OPC server. I found that this was the best solution for getting the responses back. Ignition handles the reconnecting and status in the background and the ports are always open/repaired. I send TCP message through scripting and also just write to the message tags of the OPC device tags. Then I use a tag change script on the response tag in the driver and hand the data that way.

---

<div class="post-metadata">

**Author:** ![Hayden\_Watson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hayden_watson/32/48792_2.png) [@Hayden\_Watson](https://forum.inductiveautomation.com/u/Hayden_Watson)\
**Post date:** [July 26, 2023, 6:11am UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/3 "2023-07-26T06:11:09Z")

</div>

We'd considered using the TCP device, and I had a quick look but our device has different TCP ports for different categories of commands, I wasn't sure if that would be doable as the Ignition tutorials for the TCP device make it look very basic haha.

Maybe I need to investigate it more, but I'll stick with my option 1 for now and see how it affects performance.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [July 26, 2023, 11:42am UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/4 "2023-07-26T11:42:28Z")

</div>

It is very basic. It’s mostly meant for things like barcode scanners and scales that are just blasting back strings at regular intervals.

---

<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:** [July 26, 2023, 12:39pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/5 "2023-07-26T12:39:56Z")

</div>

I would think option one should be fine for anything that runs in the once per second range or slower. Consider option two if you expect to make multiple queries per second, but you must make sure your long-lived thread exits gracefully when the hosting script module is reloaded.

Some references (with inner links):

[https://forum.inductiveautomation.com/search?q=long-lived%20thread%20persist%20order%3Alatest](https://forum.inductiveautomation.com/search?q=long-lived%20thread%20persist%20order%3Alatest)

---

<div class="post-metadata">

**Author:** ![Tim\_Carlton](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tim_carlton/32/52835_2.png) [@Tim\_Carlton](https://forum.inductiveautomation.com/u/Tim_Carlton)\
**Post date:** [July 26, 2023, 1:48pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/6 "2023-07-26T13:48:45Z")

</div>

Use a long lived connection if you need the things that TCP provides. If you can live with UDP then open and close the connection with each message will be easier to make reliable. If you can let someone else handle the connections (i.e., REST endpoints) then do that.

An open socket can fail in lots of ways. Most of those ways are silent. Asking the socket if it is still open and ok is useless - it will happily tell you that it is still connected even though the only thing that is connected is the ethernet to the closest switch. So you end up putting heartbeat messages on both ends to detect broken connections. And you listen on one port but hand that off to another on a connection and then listen on the original port again and if you get another connection while you believe that the first one is still ok then you figure out which is the real client - probably the new one and you close the old (probably dead, which the other end detected and is why it opened another one). Many of the failures are difficult to trigger so that you can test the code that automatically reconnects. And the Nagle algorithm can be a problem if you have small messages so even knowing how to turn that off or if you need to. Lots of OS dependencies.

A new socket per message can run out of ports if you are opening lots of them frequently. In some cases, the OS will not reuse a port for some period after it is closed. I don't remember how many that takes (hundreds per second? more? less?) or if it is relevant for other versions of the OS. Obviously web servers have implemented something differently to not have this issue.

HTH. And thanks for bringing back the nightmares...

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 26, 2023, 2:03pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/7 "2023-07-26T14:03:03Z")

</div>

A very critical piece of advice if you end up opening your own sockets: make sure to use Java standard library imports, adapted to Jython. Resist the temptation to use the Python standard library, **especially** for socket related code. It's buggy and prone to resource leaks.

---

<div class="post-metadata">

**Author:** ![Hayden\_Watson](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/hayden_watson/32/48792_2.png) [@Hayden\_Watson](https://forum.inductiveautomation.com/u/Hayden_Watson)\
**Post date:** [July 26, 2023, 2:24pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/8 "2023-07-26T14:24:34Z")

</div>

Some of our code is already using the python socket library

```auto
import socket

```

etc.

What module should be used instead, and do they work in a similiar way, I guess it won't be as easy as

```auto
import java.foo.bar.socket as socket

```

and then leave our code as is

Thanks!

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [July 26, 2023, 3:02pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/9 "2023-07-26T15:02:35Z")

</div>

> [@Hayden\_Watson](#):
>
> `import java.foo.bar.socket as socket`

```auto
from java.net import Socket

```

[https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html](https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html)

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [July 26, 2023, 3:12pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/10 "2023-07-26T15:12:17Z")

</div>

So the following code would be considered bad practice?

```auto
import socket
import sys

TCP_IP = '192.168.1.100'
TCP_PORT = 17001
CONNECTION_TIMEOUT = 5
		
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(CONNECTION_TIMEOUT)
s.connect((TCP_IP, TCP_PORT))
		
s.send('this is a text message')
				
s.close()
```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 26, 2023, 3:19pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/11 "2023-07-26T15:19:36Z")

</div>

Yes. It's unfortunate, but you're just setting yourself up for failure if you use `socket` directly.

Chat-GPT translated `java.net.Socket` equivalent of your snippet, that looks approximately correct:

```auto
# Jython Client using java.net.Socket

import java.net.Socket
import java.io.IOException

TCP_IP = '192.168.1.100'
TCP_PORT = 17001
CONNECTION_TIMEOUT = 5000 # The timeout is specified in milliseconds

try:
    s = Socket(TCP_IP, TCP_PORT)
    s.setSoTimeout(CONNECTION_TIMEOUT)

    out_stream = s.getOutputStream()
    message = 'this is a text message'
    out_stream.write(message.encode('utf-8'))

    s.close()

except IOException as e:
    print("Error:", e)
except Exception as e:
    print("Error:", e)

```

---

<div class="post-metadata">

**Author:** ![bmeyers](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/bmeyers/32/37453_2.png) [@bmeyers](https://forum.inductiveautomation.com/u/bmeyers)\
**Post date:** [July 26, 2023, 3:22pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/12 "2023-07-26T15:22:41Z")

</div>

That is funny. I was having ChatGPT do the same thing. I don't know enough about Java though to say if this is particularly good code.

```auto
# Import the Java Socket class from the java.net package
from java.net import Socket, InetAddress

TCP_IP = '192.168.1.100'
TCP_PORT = 17001
CONNECTION_TIMEOUT = 5000 # Milliseconds (5 seconds)

try:
    # Create a new Java Socket instance
    s = Socket()
    s.connect(InetAddress.getByName(TCP_IP), TCP_PORT, CONNECTION_TIMEOUT)

    message = 'this is a text message'
    message_bytes = message.encode('utf-8') # Convert the string to bytes with UTF-8 encoding
    s.getOutputStream().write(message_bytes) # Send the bytes through the socket's output stream
    s.getOutputStream().flush() # Ensure the data is sent immediately

except Exception as e:
    print(f"Error: {e}")

finally:
    s.close() # Close the socket after use
```

What kind of failure(s) are we talking about?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [July 26, 2023, 3:23pm UTC](https://forum.inductiveautomation.com/t/opening-sockets-to-tcp-devices-using-scripting/76860/13 "2023-07-26T15:23:36Z")

</div>

Memory leaks and socket leaks. On some platforms, most notably Windows from experience, this can lead to complete TCP starvation and an inability to open new ports.
