pymodbus-dev / pymodbus

A full modbus protocol written in python
Other
2.16k stars 889 forks source link

Hope to add a method to obtain the client's IP address on hook or callback. #2159

Closed Hermit-xx closed 2 months ago

Hermit-xx commented 2 months ago

When using TCP Server and Not binding an IP address, it is not possible to obtain the client's IP address in the callback for read/write requests. In version 2.x,I can pass a rewritten ModbusConnectedRequestHandler class to the Server, thereby passing the client's IP address to a custom request through the handler.

However, as of version 3.6.7, it is no longer possible to pass a custom Handler to the Server.

Is there a way to obtain the IP address in the every request callback? Or how can a TCPServerClass be allowed to use a custom handler? Hope to receive a solution, thanks.

this is a part of my code in v2.5.3, its work.

StartTcpServer

StartTcpServer(context=self.context,
identity=self.identity,
address=('', int(self.port)),
custom_functions=[CustomModbusRequest,CustomSingleRegisterRequest],
handler=CustomHandler)

CustomHandler

class CustomHandler(ModbusConnectedRequestHandler):
    def execute(self, request):
        broadcast = False
        try:
            if self.server.broadcast_enable and request.unit_id == 0:
                broadcast = True
                # if broadcasting then execute on all slave contexts, note response will be ignored
                for unit_id in self.server.context.slaves():
                    response = request.execute(self.server.context[unit_id])
            else:
                context = self.server.context[request.unit_id]
                if type(request).__name__ == 'CustomModbusRequest':
                    response = request.execute(context, client_address=self.client_address)
                elif type(request).__name__=='CustomSingleRegisterRequest':
                    response = request.execute(context, client_address=self.client_address)
                else:
                    response = request.execute(context)
        except NoSuchSlaveException as ex:
            myLogger.debug("requested slave does "
                           "not exist: %s" % request.unit_id)
            if self.server.ignore_missing_slaves:
                return  # the client will simply timeout waiting for a response
            response = request.doException(merror.GatewayNoResponse)
        except Exception as ex:
            myLogger.debug("Datastore unable to fulfill request: "
                           "%s; %s", ex, traceback.format_exc())
            response = request.doException(merror.SlaveFailure)
        # no response when broadcasting
        if not broadcast:
            response.transaction_id = request.transaction_id
            response.unit_id = request.unit_id
            self.send(response)
janiversen commented 2 months ago

It is not possible via the API directly. You can still add custom function requests as you did in 2.5, those will be called as usual, in those use the internal transport object to obtain the ip address.

janiversen commented 2 months ago

Closing as this is not a bug nor a feature request.