La Plateforme IoT vous permet de mettre en œuvre une pénétration pseudo-Intranet pour contrôler à distance un serveur Raspberry Pi dépourvu d'adresse IP publique. Cette rubrique explique comment utiliser la Plateforme IoT pour contrôler à distance un serveur Raspberry Pi et fournit des exemples de code.
Informations générales
Par exemple, vous utilisez un Raspberry Pi pour déployer un serveur au sein de votre entreprise ou à domicile afin d'exécuter des tâches simples, telles que le démarrage d'un script ou le téléchargement de fichiers. Si le serveur Raspberry Pi ne possède pas d'adresse IP publique et que vous n'êtes ni sur place ni chez vous, vous ne pouvez pas gérer le serveur. L'utilisation d'autres outils de pénétration Intranet peut entraîner des déconnexions fréquentes. Pour résoudre ce problème, vous pouvez utiliser la fonctionnalité RRPC de la Plateforme IoT conjointement avec la bibliothèque JSch afin de contrôler à distance le serveur Raspberry Pi.
Version héritée
Cet exemple utilise un produit et un dispositif dans une instance publique.
Procédure

La procédure suivante détaille l'utilisation de la Plateforme IoT pour contrôler à distance un serveur Raspberry Pi :
Exécutez l'opération RRPC de la Plateforme IoT sur votre ordinateur pour envoyer une commande Secure Shell (SSH).
Une fois la commande SSH reçue, la Plateforme IoT la transmet au serveur Raspberry Pi via le protocole MQTT (Message Queuing Telemetry Transport).
Le système exécute la commande SSH sur le serveur.
Le système encapsule le résultat de la commande SSH sous forme de réponse RRPC sur le serveur et envoie cette réponse à la Plateforme IoT via MQTT.
La Plateforme IoT transmet la réponse RRPC à votre ordinateur.
Le délai d'expiration RRPC est de 5 secondes. Si la Plateforme IoT ne reçoit aucune réponse du serveur Raspberry Pi dans ce délai, une erreur de temporisation se produit. Si vous envoyez une commande dont le traitement nécessite beaucoup de temps, ignorez le message d'erreur de temporisation.
Télécharger les SDK et l'exemple de code
Avant de pouvoir contrôler à distance le serveur Raspberry Pi, développez un SDK Plateforme IoT et un Link SDK.
Installez un SDK Plateforme IoT sur votre ordinateur. Vous pouvez utiliser l'exemple de code Java pour développer le SDK Plateforme IoT.
Installez un Link SDK sur le serveur Raspberry Pi. Vous pouvez utiliser l'exemple de code Java pour développer le Link SDK.
L'exemple de code suivant illustre le développement du SDK Plateforme IoT et du Link SDK.
L'exemple de code prend uniquement en charge les commandes Linux simples, telles que uname, touch et mv. Les commandes complexes, comme celles utilisées pour modifier des fichiers, ne sont pas prises en charge. Pour utiliser des commandes complexes, écrivez le code en fonction de vos besoins métier.
Développer le Link SDK
Après avoir installé le Link SDK et téléchargé l'exemple de code, ajoutez les dépendances du projet ainsi que les fichiers Java requis.
Le projet peut être exporté sous forme de package JAR et exécuté sur le serveur Raspberry Pi.
-
Ajoutez les dépendances suivantes au fichier pom.xml :
<! -- Link SDK --> <dependency> <groupId>com.aliyun.alink.linksdk</groupId> <artifactId>iot-linkkit-java</artifactId> <version>1.1.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.1</version> <scope>compile</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> <scope>compile</scope> </dependency> <! -- SSH client --> <!-- https://mvnrepository.com/artifact/com.jcraft/jsch --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency> -
Créez un fichier nommé SSHShell.java pour exécuter les commandes SSH.
public class SSHShell { private String host; private String username; private String password; private int port; private Vector<String> stdout; public SSHShell(final String ipAddress, final String username, final String password, final int port) { this.host = ipAddress; this.username = username; this.password = password; this.port = port; this.stdout = new Vector<String>(); } public int execute(final String command) { System.out.println("ssh command: " + command); int returnCode = 0; JSch jsch = new JSch(); SSHUserInfo userInfo = new SSHUserInfo(); try { Session session = jsch.getSession(username, host, port); session.setPassword(password); session.setUserInfo(userInfo); session.connect(); Channel channel = session.openChannel("exec"); ((ChannelExec) channel).setCommand(command); channel.setInputStream(null); BufferedReader input = new BufferedReader(new InputStreamReader(channel.getInputStream())); channel.connect(); String line = null; while ((line = input.readLine()) != null) { stdout.add(line); } input.close(); if (channel.isClosed()) { returnCode = channel.getExitStatus(); } channel.disconnect(); session.disconnect(); } catch (JSchException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return returnCode; } public Vector<String> getStdout() { return stdout; } } -
Créez un fichier nommé SSHUserInfo.java pour vérifier le nom d'utilisateur et le mot de passe SSH.
public class SSHUserInfo implements UserInfo { @Override public String getPassphrase() { return null; } @Override public String getPassword() { return null; } @Override public boolean promptPassphrase(final String arg0) { return false; } @Override public boolean promptPassword(final String arg0) { return false; } @Override public boolean promptYesNo(final String arg0) { if (arg0.contains("The authenticity of host")) { return true; } return false; } @Override public void showMessage(final String arg0) { } } -
Créez un fichier nommé Device.java pour établir une connexion MQTT.
public class Device { /** * Establish a connection. * * @param productKey The ProductKey of the product. * @param deviceName The DeviceName of the device. * @param deviceSecret The DeviceSecret of the device. * @throws InterruptedException */ public static void connect(String productKey, String deviceName, String deviceSecret) throws InterruptedException { // Initialize parameters. LinkKitInitParams params = new LinkKitInitParams(); // Configure the required parameters to establish an MQTT connection. IoTMqttClientConfig config = new IoTMqttClientConfig(); config.productKey = productKey; config.deviceName = deviceName; config.deviceSecret = deviceSecret; params.mqttClientConfig = config; // Specify the certificate information about the device. DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.productKey = productKey; deviceInfo.deviceName = deviceName; deviceInfo.deviceSecret = deviceSecret; params.deviceInfo = deviceInfo; // Initialize a client. LinkKit.getInstance().init(params, new ILinkKitConnectListener() { public void onError(AError aError) { System.out.println("init failed !! code=" + aError.getCode() + ",msg=" + aError.getMsg() + ",subCode=" + aError.getSubCode() + ",subMsg=" + aError.getSubMsg()); } public void onInitDone(InitResult initResult) { System.out.println("init success !!"); } }); // Before you perform the following steps, make sure that the initialization is complete. You can specify a reasonable value based on your business scenario. Thread.sleep(2000); } /** * Send a message. * @param topic The topic to which the message is sent. * @param payload The content of the message. */ public static void publish(String topic, String payload) { MqttPublishRequest request = new MqttPublishRequest(); request.topic = topic; request.payloadObj = payload; request.qos = 0; LinkKit.getInstance().getMqttClient().publish(request, new IConnectSendListener() { @Override public void onResponse(ARequest aRequest, AResponse aResponse) { } @Override public void onFailure(ARequest aRequest, AError aError) { } }); } /** * Subscribe to messages. * * @param topic The topic whose messages to which you want to subscribe. */ public static void subscribe(String topic) { MqttSubscribeRequest request = new MqttSubscribeRequest(); request.topic = topic; request.isSubscribe = true; LinkKit.getInstance().getMqttClient().subscribe(request, new IConnectSubscribeListener() { @Override public void onSuccess() { } @Override public void onFailure(AError aError) { } }); } /** * Unsubscribe from messages. * * @param topic The topic whose messages from which you want to unsubscribe. */ public static void unsubscribe(String topic) { MqttSubscribeRequest request = new MqttSubscribeRequest(); request.topic = topic; request.isSubscribe = false; LinkKit.getInstance().getMqttClient().unsubscribe(request, new IConnectUnscribeListener() { @Override public void onSuccess() { } @Override public void onFailure(AError aError) { } }); } /** * Terminate the connection. */ public static void disconnect() { // Deinitialize the parameters. LinkKit.getInstance().deinit(); } } -
Créez un fichier nommé SSHDevice.java. Le fichier SSHDevice.java inclut la méthode principale utilisée pour recevoir les commandes RRPC. Vous pouvez également appeler
SSHShellpour exécuter des commandes SSH et renvoyer des réponses RRPC. Dans le fichier SSHDevice.java, vous devez saisir les informations de certificat du dispositif ainsi que le nom d'utilisateur et le mot de passe SSH. Les informations de certificat du dispositif comprennent le ProductKey, le DeviceName et le DeviceSecret.public class SSHDevice { // ===================The start of the segment in which you configure the required parameters.=========================== // The ProductKey of the product. private static String productKey = ""; // private static String deviceName = ""; // The DeviceSecret of the device. private static String deviceSecret = ""; // The topic that you want to use for messaging. You can use the topic without the need to create or define the topic. private static String rrpcTopic = "/sys/" + productKey + "/" + deviceName + "/rrpc/request/+"; // The endpoint or the IP address to which the SSH client needs to access. private static String host = "127.0.0.1"; // The username that is used to log on to the SSH client. private static String username = ""; // The password for the username. private static String password = ""; // The number of the port that is used to log on to the SSH client. private static int port = 22; // ===================The end of the segment in which you configure the required parameters.=========================== public static void main(String[] args) throws InterruptedException { // Listen to downstream data. registerNotifyListener(); // Establish a connection. Device.connect(productKey, deviceName, deviceSecret); // Subscribe to a topic. Device.subscribe(rrpcTopic); } public static void registerNotifyListener() { LinkKit.getInstance().registerOnNotifyListener(new IConnectNotifyListener() { @Override public boolean shouldHandle(String connectId, String topic) { // Process messages only from specific topics. if (topic.contains("/rrpc/request/")) { return true; } else { return false; } } @Override public void onNotify(String connectId, String topic, AMessage aMessage) { // Receive RRPC requests and return RRPC responses. try { // Run a remote command. String payload = new String((byte[]) aMessage.getData(), "UTF-8"); SSHShell sshExecutor = new SSHShell(host, username, password, port); sshExecutor.execute(payload); // Obtain the output of the command. StringBuffer sb = new StringBuffer(); Vector<String> stdout = sshExecutor.getStdout(); for (String str : stdout) { sb.append(str); sb.append("\n"); } // Return the output to the server. String response = topic.replace("/request/", "/response/"); Device.publish(response, sb.toString()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } @Override public void onConnectStateChange(String connectId, ConnectState connectState) { } }); } }
Développer le SDK Plateforme IoT
Après avoir installé le SDK Plateforme IoT et téléchargé l'exemple de code, ajoutez les dépendances du projet ainsi que les fichiers Java requis.
-
Ajoutez les dépendances suivantes au fichier pom.xml :
ImportantPour plus d'informations sur la dernière version du SDK Plateforme IoT, consultez le
.
<! -- IoT Platform SDK --> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-iot</artifactId> <version>7.38.0</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.6</version> </dependency> <!-- commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.8</version> </dependency> -
Créez un fichier nommé OpenApiClient.java pour appeler les opérations API de la Plateforme IoT.
public class OpenApiClient { private static DefaultAcsClient client = null; public static DefaultAcsClient getClient(String accessKeyID, String accessKeySecret) { if (client != null) { return client; } try { IClientProfile profile = DefaultProfile.getProfile("cn-shanghai", accessKeyID, accessKeySecret); DefaultProfile.addEndpoint("cn-shanghai", "cn-shanghai", "Iot", "iot.cn-shanghai.aliyuncs.com"); client = new DefaultAcsClient(profile); } catch (Exception e) { System.out.println("create OpenAPI Client failed !! exception:" + e.getMessage()); } return client; } } -
Créez un fichier nommé SSHCommandSender.java. Le fichier SSHCommandSender.java inclut la méthode principale utilisée pour envoyer des commandes SSH et recevoir les réponses correspondantes. Dans le fichier SSHCommandSender.java, vous devez spécifier les informations de certificat du dispositif, la paire AccessKey de votre compte Alibaba Cloud et les commandes SSH. Les informations de certificat du dispositif comprennent le ProductKey, le DeviceName et le DeviceSecret.
public class SSHCommandSender { // ===================The start of the segment in which you configure the required parameters.=========================== // The AccessKey ID of your Alibaba Cloud account. private static String accessKeyID = ""; // The AccessKey secret of your Alibaba Cloud account. private static String accessKeySecret = ""; // The ProductKey of the product. private static String productKey = ""; // The DeviceName of the device. private static String deviceName = ""; // ===================The end of the segment in which you configure the required parameters.=========================== public static void main(String[] args) throws ServerException, ClientException, UnsupportedEncodingException { // The remote Linux command. String payload = "uname -a"; // Create an RRPC request. RRpcRequest request = new RRpcRequest(); request.setProductKey(productKey); request.setDeviceName(deviceName); request.setRequestBase64Byte(Base64.encodeBase64String(payload.getBytes())); request.setTimeout(5000); // The client that is used to receive requests from the server. DefaultAcsClient client = OpenApiClient.getClient(accessKeyID, accessKeySecret); // Send an RRPC request. RRpcResponse response = (RRpcResponse) client.getAcsResponse(request); // Process RRPC responses. // The result that is returned after the execution of the response.getSuccess() function indicates only that the RRPC request is sent. The returned response does not indicate whether the request is received by the device or whether the device returned a response based on the result. // You must check the result based on the RRPC response code that is returned. For more information, see https://www.alibabacloud.com/help/doc-detail/69797.htm. if (response != null && "SUCCESS".equals(response.getRrpcCode())) { // The output. System.out.println(new String(Base64.decodeBase64(response.getPayloadBase64Byte()), "UTF-8")); } else { // Failed to obtain the output and print the related RRPC response code. System.out.println(response.getRrpcCode()); } } }