# Using Java.net Socket

**URL:** <https://forum.inductiveautomation.com/t/using-java-net-socket/79962>\
**Category:** Ignition\
**Tags:** ignition81, scripting\
**Created:** [October 3, 2023, 7:18am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962 "2023-10-03T07:18:02Z")\
**Posts on this page:** 20\
**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:** [October 3, 2023, 7:18am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/1 "2023-10-03T07:18:02Z")

</div>

Hey all,  
I'm trying to use the java sockets for some TCP devices.

We're using the below code, our devices have a sort of API where they expect a byte array to be written.

```auto
from java.net import Socket as javaSocket
......

skt = javaSocket(ip_addr, port) #Java Socket declare, see imports at the top of module
skt.setSoTimeout(CONNECTION_TIMEOUT) #set timeout
	
out_stream = skt.getOutputStream() # set socket send data stream

out_stream.write(b_msg) # write data
out_stream.flush() # flush data down socket
	
....

```

In this section of the code, the `skt.getOutputStream().write(...)` keeps erroring saying it needs an integer, but the Java docs for this function says it can be overloaded with a byte array which our variable `b_msg` is. If I convert to an integer it doesn't work either.

How have people gotten these sockets to work on their system, I'm struggling to find documentation on the Jython for these IO functions

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 3, 2023, 9:03am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/2 "2023-10-03T09:03:34Z")

</div>

I'm not super familiar with Java and how it interacts with Jython, but the first thing that comes to my mind when reading this is that there might be a mismatch between jython's byte array (the one you're passing) and the one Java expects (failed conversion from one to the other maybe ?).  
Getting a type it's not expecting, the call is dispatched to the integer version because it's the default, which is why you get an error saying it expects an int.

I might be entirely wrong about all this, but it's worth making sure that the types do match.

---

<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:** [October 3, 2023, 9:15am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/3 "2023-10-03T09:15:14Z")

</div>

I wonder what could be different between the data types, I've imported the 'Java Concurrent Lists' before for other systems, so I'll see if we can import some kind of "Java Byte Array Type" and try to put it in there.

It does make sense that it would return that default integer not found when the overriden function gets an exception.

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 3, 2023, 9:20am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/4 "2023-10-03T09:20:51Z")

</div>

Jython's jarray might be of use.

```python
import jarray

b_msg = jarray.array(b_msg, 'b')

```

---

<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:** [October 3, 2023, 9:48am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/5 "2023-10-03T09:48:15Z")

</div>

> [@JordanCClark](#):
>
> Jython's jarray

I'll look into using that then, getting errors that the value is too large, as we're encoding a JSON into a byte array before sending

e.g.

```python
 b_msg = bytearray(raw_msg)
 if msg != {}:
     b_content = bytearray(json_str,'ascii')
     b_msg.extend(b_content)
etc....

b_msg = jarray.array(b_msg, 'b')
etc....

```

Maybe I need to use the jarray in this earlier declaration rather than type convert later? And create a Jarray of Jarray's?

---

<div class="post-metadata">

**Author:** ![JordanCClark](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/jordancclark/32/83362_2.png) [@JordanCClark](https://forum.inductiveautomation.com/u/JordanCClark)\
**Post date:** [October 3, 2023, 10:34am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/6 "2023-10-03T10:34:35Z")

</div>

Ah. Then this may be better for you.

```python
from org.python.core.util import StringUtil

b_msg = StringUtils.toBytes(raw_msg)

```

EDIT: or more likely, since I don't know what all is going into this; 😉

```python
b_msg = StringUtils.toBytes(json_str)

```

---

<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:** [October 3, 2023, 11:58am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/7 "2023-10-03T11:58:22Z")

</div>

> [@Hayden\_Watson](#):
>
> Java docs for this function says it can be overloaded with a byte array

Last I looked, jython doesn't reliably handle overloads that have the same number of arguments. You probably will need to use reflection to pick out the correct method and call it indirectly. But try Jordan's suggestion first.

---

<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:** [October 3, 2023, 12:49pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/8 "2023-10-03T12:49:22Z")

</div>

I'll have a test with this, and see how it works out then. I think we basically are uploading a JSON into bytes, but have some preamble bytes to tell the machine what the command is.

We previously used Python Sockets, but I'm needing to convert them over to Java modules.

I'll play with converting the JSON into bytes and appending that to a byte array of those premabled bytes and see if the `out_stream` accepts it

---

<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:** [October 4, 2023, 7:46am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/9 "2023-10-04T07:46:02Z")

</div>

Still had some issues with the same error, though the too large value error was fixed. So I had a mess with reflection where

```auto
from java.net import Socket as javaSocket

skt = javaSocket('8.8.8.8', 443) #Java Socket declare, see imports at the top of module

out_stream = skt.getOutputStream() # set socket send data stream

for i in out_stream.getClass().getMethods():
	if str(i).endswith('(byte[]) throws java.io.IOException') and i.getName() == 'write':
		print i
		print i.getName()
		i.invoke(?, ?)
skt.close()

```

In this instance I'm not sure what I should put as the instance name, is it anything really or should it be the `out_stream` variable?  
I was able to see my overloaded method that I need `public void java.net.SocketOutputStream.write(byte[]) throws java.io.IOException `  
But now not sure how to actually invoke it in a Jython environment.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 4, 2023, 9:44am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/10 "2023-10-04T09:44:56Z")

</div>

I'm... not sure about this, but maybe it's worth a try:

```python
write_func = next(m for m in out_stream.class.methods if m.name == "write" and m.parameterCount == 1 and not m.isDefault())

write_func.setAccessible(True)
write_func.invoke(out_stream, your_byte_array)

```

There's probably a better way to target the function, maybe based on parameter type, but java types are.... nnnggg  
Or just use `out_stream.class.methods[0]`, they should always be in the same order. I think.

---

<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:** [October 4, 2023, 10:09am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/11 "2023-10-04T10:09:01Z")

</div>

When trying to access the function using the

> [@pascal.fragnoud](#):
>
> `write_func.invoke(out_stream, your_byte_array)`

I get a nice new error:  
`org.python.core.PyReflectedFunction cannot access a member of class java.net.SocketOutputStream (in module java.base) with modifiers "public"`

Seeing as the Method I need is `public void java.net.SocketOutputStream.write(byte[]...` so a public method, does that mean this whole method is not accessible with reflection at all? Or is using the `out_stream` an incorrect instancing for this method?

Interestinly this also just ignored my `try: except:` in my script and had the exception throw like I had no error handling, rather interesting.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [October 4, 2023, 11:02am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/12 "2023-10-04T11:02:02Z")

</div>

> [@Hayden\_Watson](#):
>
> Interestinly this also just ignored my `try: except:` in my script and had the exception throw like I had no error handling, rather interesting.

Did you use `except Exception` ?  
This is likely going to throw a java error, not a python error. You'll need to catch this instead, either by importing the exact error (`java.io.IOException`) or using a general one (`from java.lang import Throwable`).

---

<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:** [October 4, 2023, 11:19am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/13 "2023-10-04T11:19:02Z")

</div>

You should not be iterating through all of the methods. Simply request the correct method with [.getMethod(java.lang.String,java.lang.Class...)](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Class.html#getMethod(java.lang.String,java.lang.Class...)). It takes the string name of the method and additional parameters matching the data types of the desired overload. Get the `type()` of an empty `jarray` of bytes to get `byte[]` to supply to the function.

---

<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:** [October 4, 2023, 12:28pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/14 "2023-10-04T12:28:16Z")

</div>

That's what suprised me, I tend to use `except java.io.IOException as e:` but it seems to be another error I guess. I'll add a generic `except` to the catch any outliers, wanting my `finally:` to fire to prevent any leaking sockets.

---

<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:** [October 4, 2023, 12:32pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/15 "2023-10-04T12:32:13Z")

</div>

I tried adding the below code as a test

```auto
b_msg = jarray.zeros(5, 'b')
print type(b_msg)
writeMethod = out_stream.getClass().getMethod('write',type(b_msg))
print writeMethod

```

When I use the above code to get the type I always get `<type 'array.array'>` am I using the Jarray incorrectly?

Seems whatever I put into the string name it errors saying that the method doesn't exist, when I use the `i.getName()` from my above loop, or if I use any part of that name. What kind of naming do I need to use for the string, or is the datatype throwing it. I tested using an `int` datatype as well but same issue

---

<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:** [October 9, 2023, 8:38am UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/16 "2023-10-09T08:38:38Z")

</div>

I've been doing some testing and resolved the issue of the invoke. I found an equivalent function which takes the length and starting bit of write bytes, so I don't need to worry about this. So `out_stream.write(b_msg,0,len(b_msg)) # Write Data`

However I continue to have issues with the `Jarray.array` to get my data into this java byte array format. In general I use the below script. Where:

```auto
def someFunc(...):
    raw_msg = struct.pack(some_packed data)
    b_msg = bytearray(raw_msg)
  
    if msg != {}:
        b_content = StringUtil.toBytes(json_str)
        b_msg.extend(b_content)
		
    return b_msg

skt = javaSocket(ip_addr, port) #Java Socket declare, see imports at the top of module
	
skt.setSoTimeout(CONNECTION_TIMEOUT) #set timeout
	
out_stream = skt.getOutputStream() # set socket send data stream
	
b_msg = jarray.array(b_msg,'b') # Create Java array object for data transmission
...

```

I continue to get an error with the `jarray.array` of the error `OverflowError: value too large for byte` at that line, when I print the byte value I get a random two characters, and the `len(b_msg)` is 16. It should just be an array of bytes, so why is this occuring?

---

<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:** [October 9, 2023, 1:01pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/17 "2023-10-09T13:01:07Z")

</div>

When constructing bytes with `jarray`, each byte must be in the range `-128..127`, not `0..255`. Bytes are signed in java.

---

<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:** [October 9, 2023, 1:54pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/18 "2023-10-09T13:54:51Z")

</div>

ah right, we're using the struct package to make this object, so I wonder if there's some formatting we can do in there before putting in the jarray, or is it as simple as:

```auto
for i in myList:
     i = int(i) - 128 # shift my byte
jarray.array(mylist, 'b')

```

---

<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:** [October 9, 2023, 2:02pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/19 "2023-10-09T14:02:33Z")

</div>

No, shifting the values by 128 is wrong. You want to leave `0..127` alone, and subtract 256 from `-128..-1`. I typically use `((i + 128) % 256) - 128`.

---

<div class="post-metadata">

**Author:** ![victordcq](https://avatars.discourse-cdn.com/v4/letter/v/f6c823/32.png) [@victordcq](https://forum.inductiveautomation.com/u/victordcq)\
**Post date:** [October 9, 2023, 2:27pm UTC](https://forum.inductiveautomation.com/t/using-java-net-socket/79962/20 "2023-10-09T14:27:33Z")

</div>

> [@Hayden\_Watson](#):
>
> java.io.IOException as e

i usually use this for error handling, this worked for me when cathcing some exotic java errors

```auto
from java.lang import Exception as JavaExpection
try:
  ...
except (JavaExpection, Exception), e:

```

[Next page](https://forum.inductiveautomation.com/t/using-java-net-socket/79962.md?page=2)
