Skip to content

Commit f1128a7

Browse files
Use non privileged tcp port in examples (#109)
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.
1 parent 4fd98ba commit f1128a7

File tree

3 files changed

+69
-22
lines changed

3 files changed

+69
-22
lines changed

README.rst

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Creating a Modbus TCP server is easy:
3636
import logging
3737
from socketserver import TCPServer
3838
from collections import defaultdict
39+
from argparse import ArgumentParser
3940
4041
from umodbus import conf
4142
from umodbus.server.tcp import RequestHandler, get_server
@@ -44,23 +45,37 @@ Creating a Modbus TCP server is easy:
4445
# Add stream handler to logger 'uModbus'.
4546
log_to_stream(level=logging.DEBUG)
4647
47-
# A very simple data store which maps addresss against their values.
48+
# A very simple data store which maps addresses against their values.
4849
data_store = defaultdict(int)
4950
5051
# Enable values to be signed (default is False).
5152
conf.SIGNED_VALUES = True
5253
53-
TCPServer.allow_reuse_address = True
54-
app = get_server(TCPServer, ('localhost', 502), RequestHandler)
54+
# Parse command line arguments
55+
parser = ArgumentParser()
56+
parser.add_argument("-b", "--bind", default="localhost:502")
5557
58+
args = parser.parse_args()
59+
if ":" not in args.bind:
60+
args.bind += ":502"
61+
host, port = args.bind.rsplit(":", 1)
62+
port = int(port)
5663
57-
@app.route(slave_ids=[1], function_codes=[3, 4], addresses=list(range(0, 10)))
64+
TCPServer.allow_reuse_address = True
65+
try:
66+
app = get_server(TCPServer, (host, port), RequestHandler)
67+
except PermissionError:
68+
print("You don't have permission to bind on {}".format(args.bind))
69+
print("Hint: try with a different port (ex: --bind localhost:50200)")
70+
exit(1)
71+
72+
@app.route(slave_ids=[1], function_codes=[1, 2], addresses=list(range(0, 10)))
5873
def read_data_store(slave_id, function_code, address):
5974
"""" Return value of address. """
6075
return data_store[address]
6176
6277
63-
@app.route(slave_ids=[1], function_codes=[6, 16], addresses=list(range(0, 10)))
78+
@app.route(slave_ids=[1], function_codes=[5, 15], addresses=list(range(0, 10)))
6479
def write_data_store(slave_id, function_code, address, value):
6580
"""" Set value for address. """
6681
data_store[address] = value
@@ -82,26 +97,34 @@ Doing a Modbus request requires even less code:
8297
8398
#!/usr/bin/env python
8499
# scripts/examples/simple_tcp_client.py
85-
import socket
100+
from argparse import ArgumentParser
101+
from socket import create_connection
86102
87103
from umodbus import conf
88104
from umodbus.client import tcp
89105
90106
# Enable values to be signed (default is False).
91107
conf.SIGNED_VALUES = True
92108
93-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
94-
sock.connect(('localhost', 502))
109+
# Parse command line arguments
110+
parser = ArgumentParser()
111+
parser.add_argument("-a", "--address", default="localhost:502")
112+
113+
args = parser.parse_args()
114+
if ":" not in args.address:
115+
args.address += ":502"
116+
host, port = args.address.rsplit(":", 1)
117+
port = int(port)
95118
96119
# Returns a message or Application Data Unit (ADU) specific for doing
97120
# Modbus TCP/IP.
98121
message = tcp.write_multiple_coils(slave_id=1, starting_address=1, values=[1, 0, 1, 1])
99122
100-
# Response depends on Modbus function code. This particular returns the
101-
# amount of coils written, in this case it is.
102-
response = tcp.send_message(message, sock)
123+
with create_connection((host, port)) as sock:
124+
# Response depends on Modbus function code. This particular returns the
125+
# amount of coils written, in this case it is.
126+
response = tcp.send_message(message, sock)
103127
104-
sock.close()
105128
106129
Features
107130
--------
Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
#!/usr/bin/env python
22
# scripts/examples/simple_tcp_client.py
3-
import socket
3+
from argparse import ArgumentParser
4+
from socket import create_connection
45

56
from umodbus import conf
67
from umodbus.client import tcp
78

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

11-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12-
sock.connect(('localhost', 502))
12+
# Parse command line arguments
13+
parser = ArgumentParser()
14+
parser.add_argument("-a", "--address", default="localhost:502")
15+
16+
args = parser.parse_args()
17+
if ":" not in args.address:
18+
args.address += ":502"
19+
host, port = args.address.rsplit(":", 1)
20+
port = int(port)
1321

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

18-
# Response depends on Modbus function code. This particular returns the
19-
# amount of coils written, in this case it is.
20-
response = tcp.send_message(message, sock)
21-
22-
sock.close()
26+
with create_connection((host, port)) as sock:
27+
# Response depends on Modbus function code. This particular returns the
28+
# amount of coils written, in this case it is.
29+
response = tcp.send_message(message, sock)

scripts/examples/simple_tcp_server.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/usr/bin/env python
2-
# scripts/examples/simple_data_store.py
2+
# scripts/examples/simple_tcp_server.py
33
import logging
44
from socketserver import TCPServer
55
from collections import defaultdict
6+
from argparse import ArgumentParser
67

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

21+
# Parse command line arguments
22+
parser = ArgumentParser()
23+
parser.add_argument("-b", "--bind", default="localhost:502")
24+
25+
args = parser.parse_args()
26+
if ":" not in args.bind:
27+
args.bind += ":502"
28+
host, port = args.bind.rsplit(":", 1)
29+
port = int(port)
30+
2031
TCPServer.allow_reuse_address = True
21-
app = get_server(TCPServer, ('localhost', 502), RequestHandler)
32+
try:
33+
app = get_server(TCPServer, (host, port), RequestHandler)
34+
except PermissionError:
35+
print("You don't have permission to bind on {}".format(args.bind))
36+
print("Hint: try with a different port (ex: --bind localhost:50200)")
37+
exit(1)
2238

2339

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

51+
3552
if __name__ == '__main__':
3653
try:
3754
app.serve_forever()

0 commit comments

Comments
 (0)