Let’s get started by sending an OPC UA TCP Hello message to localhost.
- We ‘ll be developping on Debian Squeeze with Python 2.6.6.
- We’ll be using [Wireshark](http://www.wireshark.org/), with the [OPC ua dissector](http://anonsvn.wireshark.org/viewvc/releases/wireshark-1.6.7/plugins/opcua/) to check our message.
- Note: the opc ua dissector is not yet available in Wireshark 1.2.11. This is the version used on Debian squeeze. To solve this we run Wireshark 1.6.7 on Debian Sid inside a chroot.
- You should be able to run these snippets with newer versions of python and on other platforms as well.
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:
- MessageType: HEL, from hello
- IsFinal: F, from final because the hello message is sent in 1 chunk so it is the final chunk
- MessageSize: 32 + the number of characters in the EndpointUrl
- ProtocolVersion: 0, because our stack has not been certified it’s version is 0
- ReceiverBufferSize: 9000, just an example
- SendBufferSize: 9000, just an example
- MaxMessageSize: 0, this means unlimited
- MaxChunkCount: 0, this means unlimited
- EndpointUrl: opc.tcp://opycua:4841, just an example
Using Construct we can create a struct, containing these fields.:
:::python
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.
- The first one will act as the OPC ua server. It simply waits and listens on a port. This is necessary because otherwise we cannot send a packet to this port.
- The second one will act as the OPC ua client. It will encode the field of the OPC UA hello message as binary data and send it to the listening port.
Wireshark will also be running, so we can capture the message.
Snippet:
:::python
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).
Snippet:
:::python
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:

- The socket code in this snippet is based on the [PyMOTW article on the socket module](http://www.doughellmann.com/PyMOTW/socket/tcp.html) by Doug Hellmann.
- The OPC ua dissector is created by Gerhard Gappmeier from [ascolab GmbH](http://www.ascolab.com)