Hello world!

Let’s get started by sending an OPC UA TCP Hello message to localhost.

The OPC UA Hello message

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:

Parameter Datatype Value Comments
MessageType 3 ACII bytes HEL from hello
IsFinal 1 ASCII byte F from final
MessageSize ULInt32 32+len(EndpointUrl)  
ProtocolVersion ULInt32 0 uncertified stack
ReceiverBufferSize ULInt32 65536  
SendBufferSize ULInt32 65536  
MaxMessageSize ULInt32 0 unlimited
MaxChunkCount ULInt32 0 unlimited
EndpointUrl PascalString opc.tcp://opycua:4840  

Construct

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'),
    )

Snippets

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.

STEP 1: Start listening

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

Socket code based on an article from Doug Hellmann [pymotw_socket]

STEP 2: start Wireshark

Start Wireshark and listen for OPC ua traffic [uadissector] on the loopback device (lo).

STEP 3: Send hello 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'),
    )

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

Results

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:

../_images/HelloMessage.png

Credits

[pymotw_socket]The socket code in this snippet is based on the PyMOTW article on the socket module by Doug Hellmann.
[uadissector]The OPC ua dissector is created by Gerhard Gappmeier from ascolab GmbH

Table Of Contents

Previous topic

Preparing your system

This Page