Skip to content

Commit

Permalink
Use non privileged tcp port in examples (#109)
Browse files Browse the repository at this point in the history
The server example had port 502 hard coded. This port is a privileged port.
Trying to use it without permissions could result in a failure of the example.
Port 502 is still the default, but a nice error message is printed to warn the user
about the problem. Also a flag has been introduced to change the port.

To keep the example client working with the example server code a similar
change has been made to the example client.
  • Loading branch information
tiagocoutinho committed Nov 11, 2020
1 parent 4fd98ba commit f1128a7
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 22 deletions.
47 changes: 35 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Creating a Modbus TCP server is easy:
import logging
from socketserver import TCPServer
from collections import defaultdict
from argparse import ArgumentParser
from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
Expand All @@ -44,23 +45,37 @@ Creating a Modbus TCP server is easy:
# Add stream handler to logger 'uModbus'.
log_to_stream(level=logging.DEBUG)
# A very simple data store which maps addresss against their values.
# A very simple data store which maps addresses against their values.
data_store = defaultdict(int)
# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True
TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('localhost', 502), RequestHandler)
# Parse command line arguments
parser = ArgumentParser()
parser.add_argument("-b", "--bind", default="localhost:502")
args = parser.parse_args()
if ":" not in args.bind:
args.bind += ":502"
host, port = args.bind.rsplit(":", 1)
port = int(port)
@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 10)))
TCPServer.allow_reuse_address = True
try:
app = get_server(TCPServer, (host, port), RequestHandler)
except PermissionError:
print("You don't have permission to bind on {}".format(args.bind))
print("Hint: try with a different port (ex: --bind localhost:50200)")
exit(1)
@app.route(slave_ids=[1], function_codes=[1, 2], addresses=list(range(0, 10)))
def read_data_store(slave_id, function_code, address):
"""" Return value of address. """
return data_store[address]
@app.route(slave_ids=[1], function_codes=[6, 16], addresses=list(range(0, 10)))
@app.route(slave_ids=[1], function_codes=[5, 15], addresses=list(range(0, 10)))
def write_data_store(slave_id, function_code, address, value):
"""" Set value for address. """
data_store[address] = value
Expand All @@ -82,26 +97,34 @@ Doing a Modbus request requires even less code:
#!/usr/bin/env python
# scripts/examples/simple_tcp_client.py
import socket
from argparse import ArgumentParser
from socket import create_connection
from umodbus import conf
from umodbus.client import tcp
# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 502))
# Parse command line arguments
parser = ArgumentParser()
parser.add_argument("-a", "--address", default="localhost:502")
args = parser.parse_args()
if ":" not in args.address:
args.address += ":502"
host, port = args.address.rsplit(":", 1)
port = int(port)
# Returns a message or Application Data Unit (ADU) specific for doing
# Modbus TCP/IP.
message = tcp.write_multiple_coils(slave_id=1, starting_address=1, values=[1, 0, 1, 1])
# Response depends on Modbus function code. This particular returns the
# amount of coils written, in this case it is.
response = tcp.send_message(message, sock)
with create_connection((host, port)) as sock:
# Response depends on Modbus function code. This particular returns the
# amount of coils written, in this case it is.
response = tcp.send_message(message, sock)
sock.close()
Features
--------
Expand Down
23 changes: 15 additions & 8 deletions scripts/examples/simple_tcp_client.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
#!/usr/bin/env python
# scripts/examples/simple_tcp_client.py
import socket
from argparse import ArgumentParser
from socket import create_connection

from umodbus import conf
from umodbus.client import tcp

# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('localhost', 502))
# Parse command line arguments
parser = ArgumentParser()
parser.add_argument("-a", "--address", default="localhost:502")

args = parser.parse_args()
if ":" not in args.address:
args.address += ":502"
host, port = args.address.rsplit(":", 1)
port = int(port)

# Returns a message or Application Data Unit (ADU) specific for doing
# Modbus TCP/IP.
message = tcp.write_multiple_coils(slave_id=1, starting_address=1, values=[1, 0, 1, 1])

# Response depends on Modbus function code. This particular returns the
# amount of coils written, in this case it is.
response = tcp.send_message(message, sock)

sock.close()
with create_connection((host, port)) as sock:
# Response depends on Modbus function code. This particular returns the
# amount of coils written, in this case it is.
response = tcp.send_message(message, sock)
21 changes: 19 additions & 2 deletions scripts/examples/simple_tcp_server.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env python
# scripts/examples/simple_data_store.py
# scripts/examples/simple_tcp_server.py
import logging
from socketserver import TCPServer
from collections import defaultdict
from argparse import ArgumentParser

from umodbus import conf
from umodbus.server.tcp import RequestHandler, get_server
Expand All @@ -17,8 +18,23 @@
# Enable values to be signed (default is False).
conf.SIGNED_VALUES = True

# Parse command line arguments
parser = ArgumentParser()
parser.add_argument("-b", "--bind", default="localhost:502")

args = parser.parse_args()
if ":" not in args.bind:
args.bind += ":502"
host, port = args.bind.rsplit(":", 1)
port = int(port)

TCPServer.allow_reuse_address = True
app = get_server(TCPServer, ('localhost', 502), RequestHandler)
try:
app = get_server(TCPServer, (host, port), RequestHandler)
except PermissionError:
print("You don't have permission to bind on {}".format(args.bind))
print("Hint: try with a different port (ex: --bind localhost:50200)")
exit(1)


@app.route(slave_ids=[1], function_codes=[1, 2], addresses=list(range(0, 10)))
Expand All @@ -32,6 +48,7 @@ def write_data_store(slave_id, function_code, address, value):
"""" Set value for address. """
data_store[address] = value


if __name__ == '__main__':
try:
app.serve_forever()
Expand Down

0 comments on commit f1128a7

Please sign in to comment.