Let's get started by sending an OPC UA TCP Hello message to localhost.
The hello message is used to negotiate buffer size, message size, and the maximum number of chunks per message to use.
It contains the following fields:
Using Construct we can create a struct, containing these fields.
from construct import *
c = Struct('OPC UA TCP Hello Message',
String('MessageType', 3),
String('Reserved', 1),
ULInt32('MessageSize'),
ULInt32('ProtocolVersion'),
ULInt32('ReceiveBufferSize'),
ULInt32('SendBufferSize'),
ULInt32('MaxMessageSize'),
ULInt32('MaxChunkCount'),
PascalString('EndpointUrl', length_field=ULInt32('length'), encoding='utf8'),
)
We 'll be using 2 snippets.
Wireshark will also be running, so we can capture the message.
import socket
import sys
from construct import *
c = Struct('OPC UA TCP Hello Message',
String('MessageType', 3),
String('Reserved', 1),
ULInt32('MessageSize'),
ULInt32('ProtocolVersion'),
ULInt32('ReceiveBufferSize'),
ULInt32('SendBufferSize'),
ULInt32('MaxMessageSize'),
ULInt32('MaxChunkCount'),
PascalString('EndpointUrl', length_field=ULInt32('length'), encoding='utf8'),
)
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 4840)
sock.bind(server_address)
sock.listen(1)
while True:
print >>sys.stderr, '\nwaiting for a connection'
connection, client_address = sock.accept()
try:
data = connection.recv(53)
print >>sys.stderr, 'received "%s"' % data
unpacked_data = c.parse(data)
print >>sys.stderr, 'unpacked:', unpacked_data
finally:
connection.close()
Listen on the loopback device (lo).
import socket
import sys
from construct import *
c = Struct('OPC UA TCP Hello Message',
String('MessageType', 3),
String('Reserved', 1),
ULInt32('MessageSize'),
ULInt32('ProtocolVersion'),
ULInt32('ReceiveBufferSize'),
ULInt32('SendBufferSize'),
ULInt32('MaxMessageSize'),
ULInt32('MaxChunkCount'),
PascalString('EndpointUrl', length_field=ULInt32('length'), encoding='utf8'),
)
x = Container(
MessageType = 'HEL' ,
Reserved = 'F' ,
MessageSize = 53 ,
ProtocolVersion = 0 ,
ReceiveBufferSize = 9000 ,
SendBufferSize = 9000 ,
MaxMessageSize = 0 ,
MaxChunkCount = 0 ,
EndpointUrl = 'opc.tcp://opycua:4841',
)
packed_data = c.build(x)
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 4840)
sock.connect(server_address)
try:
# Send data
print >>sys.stderr, 'sending "%s"' % packed_data
sock.sendall(packed_data)
finally:
print >>sys.stderr, 'closing socket'
sock.close()
We hope this little example shows that it is a great idea to implement an OPC ua stack in python.
Anyway, here is a screenshot from Wireshark:
