我正在尝试通过 Delphi 中的 TMS MQTT 连接到 Azure IoTHub。每次都会出现“连接丢失”的情况。我尝试了两种方法:使用证书和连接字符串。
例如我的代码使用证书创建客户端:
FMQTTClient := TTMSMQTTClient.Create(nil);
FMQTTClient.BrokerHostName := Format('%s.azure-devices.net', \[FIoTHubHostName\]);
FMQTTClient.BrokerPort := 443; // also tried 8883, got "csConnectionRejected_ClientNotAuthorized"
FMQTTClient.ClientID := FMyDeviceId;
FMQTTClient.OnConnectedStatusChanged := OnConnectedStatusChanged;
FMQTTClient.OnPublishReceived := OnMessageReceived;
FMQTTClient.OnSSLIOHandlerConfiguration := OnSSLIOHandlerConfiguration;
FMQTTClient.KeepAliveSettings.AutoReconnect:= True;
FMQTTClient.KeepAliveSettings.KeepAliveInterval := 30;
FMQTTClient.KeepAliveSettings.KeepConnectionAlive := True;
FMQTTClient.Credentials.Username :=
Format('%s.azure-devices.net/%s/?api-version=2020-09-30', \[FIoTHubHostName, FMyDeviceId\]);
// Password is not needed for client certificate authentication
FMQTTClient.Credentials.Password := '';
if not IdSSLOpenSSLHeaders.Load then
raise Exception.Create('Failed to load OpenSSL');
if not IsOpenSSL_TLSv1_2_Available then
raise Exception.Create('TLSv1_2 is not available');
FMQTTClient.UseSSL := True;
BYW,使用此证书在 Python 上编写的类似客户端可以工作,所以我认为这不是根本原因。
以及配置 SSL 连接的代码:
procedure TMQTTClient.OnSSLIOHandlerConfiguration(ASender: TObject;
var ASSLIOHandler: TIdSSLIOHandlerSocketOpenSSL);
begin
ASSLIOHandler.SSLOptions.CertFile := FCertFileName; // Device certificate
ASSLIOHandler.SSLOptions.KeyFile := FKeyFileName; // Device private key
ASSLIOHandler.SSLOptions.Mode := sslmClient;
ASSLIOHandler.SSLOptions.Method := sslvTLSv1_2;
end;
但是每次我在这里得到“csConnectionLost”:
procedure TMQTTClient.OnConnectedStatusChanged(ASender: TObject;
const AConnected: Boolean; AStatus: TTMSMQTTConnectionStatus);
var
lConnStr: string;
begin
if AConnected {and (AStatus = csConnected)} then
begin
ShowMessage('Connected: True');
if FMQTTClient.Subscribe('$iothub/methods/POST/#') > 0 then
ShowMessage('Subscribe: Ok')
else
ShowMessage('Subscribe: Error');
end
else
if not AConnected then
begin
// The client is NOT connected and any interaction with the broker will result in an exception.
case AStatus of
csConnectionRejected_InvalidProtocolVersion: lConnStr := 'ConnectionRejected_InvalidProtocolVersion';
csConnectionRejected_InvalidIdentifier : lConnStr := 'ConnectionRejected_InvalidIdentifier';
csConnectionRejected_ServerUnavailable : lConnStr := 'ConnectionRejected_ServerUnavailable';
csConnectionRejected_InvalidCredentials : lConnStr := 'ConnectionRejected_InvalidCredentials';
csConnectionRejected_ClientNotAuthorized : lConnStr := 'ConnectionRejected_ClientNotAuthorized'; // the connection is rejected by broker
csConnectionLost : lConnStr := 'ConnectionLost'; // the connection with the broker is lost
csConnecting : lConnStr := 'Connecting'; // The client is trying to connect to the broker
csReconnecting : lConnStr := 'Reconnecting'; // The client is trying to reconnect to the broker
else
lConnStr := 'Unknown status:' + IntToStr(Integer(AStatus));
end;
ShowMessage('Status: ' + lConnStr);
end;
end;
小伙伴们有什么想法吗?
请告诉我我在这里做错了什么。感谢任何帮助。
我按照此 MSDOC 使用 MQTT 通过共享访问签名与 Azure IoT 中心进行通信。
我还按照这个 GitHub 存储库 在 Delphi 中使用 MQTT 客户端。
下面是通过 MQTT 连接到 Azure IoT Hub 并向设备发送指定消息的 Delphi 代码。
const
IOT_HUB_NAME = "{iothub_name}";
IOT_HUB_DEVICE_ID = "{device_id}";
IOT_HUB_SAS_TOKEN = SharedAccessSignature sr=...&sig=...&se=...';
MQTT_BROKER = IOT_HUB_NAME + '.azure-devices.net';
MQTT_PORT = 8883;
var
MQTTClient: TMQTTClient;
SSL: TIdSSLIOHandlerSocketOpenSSL;
Messages: array[0..4] of string;
I: Integer;
PublishResult: Boolean;
procedure OnConnect(Sender: TObject);
begin
WriteLn('Connected to IoT Hub');
end;
procedure OnDisconnect(Sender: TObject);
begin
WriteLn('Disconnected from IoT Hub');
end;
procedure OnPublish(Sender: TObject; const Topic: string; const Payload: string);
begin
WriteLn('Published to topic: ' + Topic + ' with payload: ' + Payload);
end;
begin
try
MQTTClient := TMQTTClient.Create(nil);
try
MQTTClient.OnConnect := OnConnect;
MQTTClient.OnDisconnect := OnDisconnect;
MQTTClient.OnPublish := OnPublish;
SSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
try
SSL.SSLOptions.Method := sslvTLSv1_2;
SSL.SSLOptions.VerifyMode := [];
MQTTClient.IOHandler := SSL;
MQTTClient.Username := IOT_HUB_NAME + '.azure-devices.net/' + IOT_HUB_DEVICE_ID + '/?api-version=2021-04-12';
MQTTClient.Password := IOT_HUB_SAS_TOKEN;
MQTTClient.Connect(MQTT_BROKER, MQTT_PORT);
Messages[0] := 'Accio';
Messages[1] := 'Aguamenti';
Messages[2] := 'Alarte Ascendare';
Messages[3] := 'Expecto Patronum';
Messages[4] := 'Homenum Revelio';
for I := Low(Messages) to High(Messages) do
begin
WriteLn('Sending message[' + IntToStr(I) + ']: ' + Messages[I]);
PublishResult := MQTTClient.Publish('devices/' + IOT_HUB_DEVICE_ID + '/messages/events/', Messages[I]);
if PublishResult then
WriteLn('Message sent successfully')
else
WriteLn('Failed to send message');
Sleep(1000);
end;
MQTTClient.Disconnect;
finally
SSL.Free;
end;
finally
MQTTClient.Free;
end;
except
on E: Exception do
WriteLn('Error: ' + E.Message);
end;
end.
输出: