Skip to content

Commit e852565

Browse files
authored
transport listen in server. (#1628)
1 parent 086c6db commit e852565

27 files changed

+653
-497
lines changed

API_changes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Version 3.4.0
99
- Modbue<x>Server handler=, allow_reuse_addr=, backlog= are no longer accepted
1010
- ModbusTcpClient / AsyncModbusTcpClient no longer support unix path
1111
- StartAsyncUnixServer / ModbusUnixServer removed (never worked on Windows)
12-
- ModbusTlsServer reqclicert= is not longer accepted
12+
- ModbusTlsServer reqclicert= is no longer accepted
13+
- ModbusSerialServer auto_connect= is no longer accepted
1314

1415

1516
-------------

doc/source/library/simulator/config.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ Server configuration examples
104104
"parity": "N",
105105
"baudrate": 9600,
106106
"timeout": 3,
107-
"auto_reconnect": false,
108107
"reconnect_delay": 2,
109108
"framer": "rtu",
110109
"identity": {

examples/client_async.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@
33
44
An example of a asynchronous client.
55
6-
usage: client_async.py [-h] [--comm {tcp,udp,serial,tls}]
7-
[--framer {ascii,binary,rtu,socket,tls}]
8-
[--log {critical,error,warning,info,debug}]
9-
[--port PORT]
6+
usage: client_async.py [-h] [-c {tcp,udp,serial,tls}]
7+
[-f {ascii,binary,rtu,socket,tls}]
8+
[-l {critical,error,warning,info,debug}] [-p PORT]
9+
[--baudrate BAUDRATE] [--host HOST]
10+
11+
Run asynchronous client.
12+
1013
options:
1114
-h, --help show this help message and exit
12-
--comm {tcp,udp,serial,tls}
13-
"serial", "tcp", "udp" or "tls"
14-
--framer {ascii,binary,rtu,socket,tls}
15-
"ascii", "binary", "rtu", "socket" or "tls"
16-
--log {critical,error,warning,info,debug}
17-
"critical", "error", "warning", "info" or "debug"
18-
--port PORT the port to use
19-
--baudrate BAUDRATE the baud rate to use for the serial device
15+
-c {tcp,udp,serial,tls}, --comm {tcp,udp,serial,tls}
16+
set communication, default is tcp
17+
-f {ascii,binary,rtu,socket,tls}, --framer {ascii,binary,rtu,socket,tls}
18+
set framer, default depends on --comm
19+
-l {critical,error,warning,info,debug}, --log {critical,error,warning,info,debug}
20+
set log level, default is info
21+
-p PORT, --port PORT set port
22+
--baudrate BAUDRATE set serial device baud rate
23+
--host HOST set host, default is 127.0.0.1
2024
2125
The corresponding server must be started before e.g. as:
2226
python3 server_sync.py

examples/client_sync.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,24 @@
33
44
An example of a single threaded synchronous client.
55
6-
usage: client_sync.py [-h] [--comm {tcp,udp,serial,tls}]
7-
[--framer {ascii,binary,rtu,socket,tls}]
8-
[--log {critical,error,warning,info,debug}]
9-
[--port PORT]
6+
usage: client_sync.py [-h] [-c {tcp,udp,serial,tls}]
7+
[-f {ascii,binary,rtu,socket,tls}]
8+
[-l {critical,error,warning,info,debug}] [-p PORT]
9+
[--baudrate BAUDRATE] [--host HOST]
10+
11+
Run asynchronous client.
12+
1013
options:
1114
-h, --help show this help message and exit
12-
--comm {tcp,udp,serial,tls}
13-
"serial", "tcp", "udp" or "tls"
14-
--framer {ascii,binary,rtu,socket,tls}
15-
"ascii", "binary", "rtu", "socket" or "tls"
16-
--log {critical,error,warning,info,debug}
17-
"critical", "error", "warning", "info" or "debug"
18-
--port PORT the port to use
19-
--baudrate BAUDRATE the baud rate to use for the serial device
15+
-c {tcp,udp,serial,tls}, --comm {tcp,udp,serial,tls}
16+
set communication, default is tcp
17+
-f {ascii,binary,rtu,socket,tls}, --framer {ascii,binary,rtu,socket,tls}
18+
set framer, default depends on --comm
19+
-l {critical,error,warning,info,debug}, --log {critical,error,warning,info,debug}
20+
set log level, default is info
21+
-p PORT, --port PORT set port
22+
--baudrate BAUDRATE set serial device baud rate
23+
--host HOST set host, default is 127.0.0.1
2024
2125
The corresponding server must be started before e.g. as:
2226
python3 server_sync.py

examples/helper.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ def get_commandline(server=False, description=None, extras=None, cmdline=None):
6363
default=9600,
6464
type=int,
6565
)
66+
parser.add_argument(
67+
"--host",
68+
help="set host, default is 127.0.0.1",
69+
dest="host",
70+
default=None,
71+
type=str,
72+
)
6673
if server:
6774
parser.add_argument(
6875
"--store",
@@ -83,14 +90,6 @@ def get_commandline(server=False, description=None, extras=None, cmdline=None):
8390
help="ADVANCED USAGE: set datastore context object",
8491
default=None,
8592
)
86-
else:
87-
parser.add_argument(
88-
"--host",
89-
help="set host, default is 127.0.0.1",
90-
dest="host",
91-
default="127.0.0.1",
92-
type=str,
93-
)
9493
if extras:
9594
for extra in extras:
9695
parser.add_argument(extra[0], **extra[1])
@@ -116,6 +115,8 @@ def get_commandline(server=False, description=None, extras=None, cmdline=None):
116115
args.port = args.port or comm_defaults[args.comm][1]
117116
if args.comm != "serial" and args.port:
118117
args.port = int(args.port)
118+
if not args.host:
119+
args.host = "" if server else "127.0.0.1"
119120
return args
120121

121122

examples/server_async.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async def run_async_server(args):
145145
txt = f"### start ASYNC server, listening on {args.port} - {args.comm}"
146146
_logger.info(txt)
147147
if args.comm == "tcp":
148-
address = ("", args.port) if args.port else None
148+
address = (args.host if args.host else "", args.port if args.port else None)
149149
server = await StartAsyncTcpServer(
150150
context=args.context, # Data storage
151151
identity=args.identity, # server identify
@@ -160,7 +160,10 @@ async def run_async_server(args):
160160
# TBD strict=True, # use strict timing, t1.5 for Modbus RTU
161161
)
162162
elif args.comm == "udp":
163-
address = ("127.0.0.1", args.port) if args.port else None
163+
address = (
164+
args.host if args.host else "127.0.0.1",
165+
args.port if args.port else None,
166+
)
164167
server = await StartAsyncUdpServer(
165168
context=args.context, # Data storage
166169
identity=args.identity, # server identify
@@ -192,7 +195,7 @@ async def run_async_server(args):
192195
# strict=True, # use strict timing, t1.5 for Modbus RTU
193196
)
194197
elif args.comm == "tls":
195-
address = ("", args.port) if args.port else None
198+
address = (args.host if args.host else "", args.port if args.port else None)
196199
server = await StartAsyncTlsServer(
197200
context=args.context, # Data storage
198201
host="localhost", # define tcp address where to connect to.

examples/simple_async_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,4 @@ async def run_async_client(host, port):
129129

130130

131131
if __name__ == "__main__":
132-
asyncio.run(run_async_client("127.0.0.1", "5020"), debug=True)
132+
asyncio.run(run_async_client("127.0.0.1", 5020), debug=True)

pymodbus/client/base.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
from pymodbus.logging import Log
1414
from pymodbus.pdu import ModbusRequest, ModbusResponse
1515
from pymodbus.transaction import DictTransactionManager
16-
from pymodbus.transport.transport import CommParams, Transport
16+
from pymodbus.transport.transport import CommParams, ModbusProtocol
1717
from pymodbus.utilities import ModbusTransactionState
1818

1919

20-
class ModbusBaseClient(ModbusClientMixin, Transport):
20+
class ModbusBaseClient(ModbusClientMixin, ModbusProtocol):
2121
"""**ModbusBaseClient**
2222
2323
**Parameters common to all clients**:
@@ -88,24 +88,26 @@ def __init__( # pylint: disable=too-many-arguments
8888
) -> None:
8989
"""Initialize a client instance."""
9090
ModbusClientMixin.__init__(self)
91-
Transport.__init__(
92-
self,
93-
CommParams(
94-
comm_type=kwargs.get("CommType"),
95-
comm_name="comm",
96-
reconnect_delay=reconnect_delay,
97-
reconnect_delay_max=reconnect_delay_max,
98-
timeout_connect=timeout,
99-
host=kwargs.get("host", None),
100-
port=kwargs.get("port", None),
101-
sslctx=kwargs.get("sslctx", None),
102-
baudrate=kwargs.get("baudrate", None),
103-
bytesize=kwargs.get("bytesize", None),
104-
parity=kwargs.get("parity", None),
105-
stopbits=kwargs.get("stopbits", None),
106-
),
107-
False,
108-
)
91+
self.use_sync = kwargs.get("use_sync", False)
92+
if not self.use_sync:
93+
ModbusProtocol.__init__(
94+
self,
95+
CommParams(
96+
comm_type=kwargs.get("CommType"),
97+
comm_name="comm",
98+
reconnect_delay=reconnect_delay,
99+
reconnect_delay_max=reconnect_delay_max,
100+
timeout_connect=timeout,
101+
host=kwargs.get("host", None),
102+
port=kwargs.get("port", None),
103+
sslctx=kwargs.get("sslctx", None),
104+
baudrate=kwargs.get("baudrate", None),
105+
bytesize=kwargs.get("bytesize", None),
106+
parity=kwargs.get("parity", None),
107+
stopbits=kwargs.get("stopbits", None),
108+
),
109+
False,
110+
)
109111
self.framer = framer
110112
self.params = self._params()
111113
self.params.timeout = float(timeout)
@@ -130,7 +132,6 @@ def __init__( # pylint: disable=too-many-arguments
130132
)
131133
self.reconnect_delay = self.params.reconnect_delay
132134
self.reconnect_delay_current = self.params.reconnect_delay
133-
self.use_sync = False
134135
self.use_udp = False
135136
self.state = ModbusTransactionState.IDLE
136137
self.last_frame_end: float = 0
@@ -139,6 +140,11 @@ def __init__( # pylint: disable=too-many-arguments
139140
# ----------------------------------------------------------------------- #
140141
# Client external interface
141142
# ----------------------------------------------------------------------- #
143+
@property
144+
def connected(self):
145+
"""Connect internal."""
146+
return True
147+
142148
def register(self, custom_response_class: ModbusResponse) -> None:
143149
"""Register a custom response class with the decoder (call **sync**).
144150
@@ -172,7 +178,7 @@ def execute(self, request: ModbusRequest = None) -> ModbusResponse:
172178
:raises ConnectionException: Check exception text.
173179
"""
174180
if self.use_sync:
175-
if not self.connect():
181+
if not self.connected:
176182
raise ConnectionException(f"Failed to connect[{str(self)}]")
177183
return self.transaction.execute(request)
178184
if not self.transport:

pymodbus/client/serial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ def __init__(
137137
) -> None:
138138
"""Initialize Modbus Serial Client."""
139139
self.transport = None
140+
kwargs["use_sync"] = True
140141
super().__init__(framer=framer, **kwargs)
141142
self.params.port = port
142143
self.params.baudrate = baudrate
@@ -145,7 +146,6 @@ def __init__(
145146
self.params.stopbits = stopbits
146147
self.params.handle_local_echo = handle_local_echo
147148
self.socket = None
148-
self.use_sync = True
149149

150150
self.last_frame_end = None
151151

pymodbus/client/tcp.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,13 @@ def __init__(
111111
**kwargs: Any,
112112
) -> None:
113113
"""Initialize Modbus TCP Client."""
114-
super().__init__(framer=framer, **kwargs)
114+
kwargs["use_sync"] = True
115+
self.transport = None
116+
super().__init__(framer=framer, host=host, port=port, **kwargs)
115117
self.params.host = host
116118
self.params.port = port
117119
self.params.source_address = source_address
118120
self.socket = None
119-
self.use_sync = True
120121

121122
@property
122123
def connected(self):

0 commit comments

Comments
 (0)