IoT Platformを使用すると、パブリックIPアドレスを持たないRaspberry Piサーバーをリモート制御するための疑似イントラネット侵入を実装できます。 このトピックでは、IoT Platformを使用してRaspberry Piサーバーをリモート制御する方法と、サンプルコードについて説明します。
背景情報
たとえば、Raspberry Piを使用して会社または自宅でサーバーを構築し、スクリプトの開始やファイルのダウンロードなどの簡単なタスクを実行します。 Raspberry PiサーバーにパブリックIPアドレスがなく、社内または自宅にいない場合は、サーバーを管理できません。 他のイントラネット挿入ツールを使用すると、切断が頻繁に発生する可能性があります。 この問題を解決するには、IoT PlatformのRRPC機能をJSchライブラリとともに使用して、Raspberry Piサーバーをリモート制御します。
処理中

次のプロセスは、IoT Platformを使用してRaspberry Piサーバーをリモート制御する方法を示しています。
- コンピューターでIoT PlatformのRRPC操作を呼び出して、Secure Shell (SSH) コマンドを送信します。
- IoT PlatformがSSHコマンドを受信すると、IoT Platformは、MQTT (Message Queuing Telemetry Transport) を介してRaspberry PiサーバーにSSHコマンドを送信します。
- システムはサーバー上でSSHコマンドを実行します。
- システムは、SSHコマンドの結果をサーバー上のRRPC応答としてカプセル化し、MQTTを介してIoT Platformに応答を送信します。
- IoT Platformは、RRPC応答をコンピューターに送信します。
SDKとサンプルコードのダウンロード
Raspberry Piサーバーをリモート制御する前に、IoT Platform SDKとLink SDKを開発してください。
- コンピューターにIoT Platform SDKをインストールします。 Javaサンプルコードを使用して、IoT Platform SDKを開発できます。
- Raspberry PiサーバーにLink SDKをインストールします。 Javaサンプルコードを使用して、Link SDKを開発できます。
次のサンプルコードは、IoT Platform SDKとLink SDKの開発方法を示しています。
リンクSDKの開発
Link SDKをインストールしてサンプルコードをダウンロードしたら、プロジェクトの依存関係と必要なJavaファイルを追加します。
プロジェクトはJARパッケージとしてエクスポートし、Raspberry Piサーバーで実行できます。
- 次の依存関係をpom.xmlファイルに追加します。
<! -- リンクSDK --> <dependency> <groupId>com.aliyun.alink.linksdk</groupId> <artifactId>iot-linkkit-java</artifactId> <version>1.1.0</version> <scope> コンパイル </scope> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.1</version> <scope> コンパイル </scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> <scope> コンパイル </scope> </dependency> <! -- SSHクライアント --> <!-https://mvnrepository.com/artifact/com.jcraft/jsch-> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.55</version> </dependency>
- SSHShell.javaという名前のファイルを作成し、SSHコマンドを実行します。
パブリッククラスSSHShell { プライベートStringホスト; プライベート文字列ユーザー名; プライベート文字列パスワード。 プライベートintポート; プライベートベクトル <String> stdout; public SSHShell(final String ipAddress、final String username、final String password、final int port) { this.host = ipAddress; this.us ername = username; this.password=パスワード; this.port = port; this.stdout = new Vector<String>(); } public int execute(final Stringコマンド) { System.out.println("ssh command: " + command); int returnCode = 0; JSch jsch = new JSch(); SSHUserInfo userInfo=新しいSSHUserInfo(); try { Session session = jsch.getSession (ユーザー名、ホスト、ポート); session.setPassword (パスワード); session.setUserInfo(userInfo); session.connect(); Channel channel = session.openChannel("exec"); ((ChannelExec) チャネル).setCommand (コマンド); channel.setInputStream(null); BufferedReader input = new BufferedReader(new InputStreamReader(channel.getInputStream())); channel.connect(); String line = null; while (((line = input.readLine())) != null) { stdout.add (ライン); } input.close(); if (channel.isClosed()) { returnCode = channel.getExitStatus(); } channel.disconnect(); session.disconnect(); } catch (JSchException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } リターンreturnCode; } publicベクトル <String> getStdout() { stdoutを返します。 } }
- SSHUserInfo.javaという名前のファイルを作成し、SSHユーザー名とパスワードを確認します。
パブリッククラスSSHUserInfoはUserInfoを実装します { @オーバーライド public文字列getPassphrase() { ヌルを返します。 } @オーバーライド public String getPassword() { ヌルを返します。 } @オーバーライド public boolean promptPassphrase(final String arg0) { return false; } @オーバーライド public boolean promptPassword(final String arg0) { return false; } @オーバーライド public boolean promptYesNo(final String arg0) { if (arg0.contains("ホストの信頼性")) { return true; } return false; } @オーバーライド public void showMessage(final String arg0) { } }
- Device.javaという名前のファイルを作成してMQTT接続を確立します。
public class Device { /** * 接続を確立します。 * * @ param productKeyプロダクトのProductKey。 * @ param deviceNameデバイスのDeviceName。 * @ param deviceSecretデバイスのDeviceSecret。 * @ throws InterruptedException */ public static void connect(String productKey, String deviceName, String deviceSecret) throws InterruptedException { // パラメーターを初期化します。 LinkKitInitParams params = new LinkKitInitParams(); // MQTT接続を確立するために必要なパラメータを設定します。 IoTMqttClientConfig config = new IoTMqttClientConfig(); config.productKey = productKey; config.de viceName = deviceName; config.de viceSecret = deviceSecret; params.mqttClientConfig = config; // デバイスに関する証明書情報を指定します。 DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.productKey = productKey; deviceInfo.deviceName = deviceName; deviceInfo.de viceSecret = deviceSecret; params.deviceInfo = deviceInfo; // クライアントを初期化します。 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 !!"); } }); // 次の手順を実行する前に、初期化が完了していることを確認してください。 ビジネスシナリオに基づいて妥当な値を指定できます。 Thread.sleep(2000); } /** * メッセージを送信します。 * @ paramトピックメッセージの送信先のトピック。 * @ param payloadメッセージの内容。 */ public static void publish(Stringトピック, String payload) { MqttPublishRequest request = new MqttPublishRequest(); request.topic = topic; request.payloadObj = payload; request.qos = 0; LinkKit.getInstance().getMqttClient().publish(request, new IConnectSendListener() { @オーバーライド public void onResponse(ARequest aRequest, AResponse aResponse) { } @オーバーライド public void onFailure(ARequest aRequest, AError aError) { } }); } /** * メッセージを購読します。 * * @ paramトピックメッセージを購読するトピック。 */ public static void subscribe (文字列トピック) { MqttSubscribeRequest request = new MqttSubscribeRequest(); request.topic = topic; request.isSubscribe = true; LinkKit.getInstance().getMqttClient().subscribe(request, new IConnectSubscribeListener() { @オーバーライド public void onSuccess() { } @オーバーライド public void onFailure(AError aError) { } }); } /** * メッセージからの購読解除。 * * @ paramトピックメッセージを配信解除するトピック。 */ public static void subscribe (文字列トピック) { MqttSubscribeRequest request = new MqttSubscribeRequest(); request.topic = topic; request.isSubscribe = false; LinkKit.getInstance().getMqttClient(). subscribe(request, new IConnectUnscribeListener() { @オーバーライド public void onSuccess() { } @オーバーライド public void onFailure(AError aError) { } }); } /** * 接続を終了します。 */ public static void disconnect() { // パラメータの初期化を解除します。 LinkKit.getInstance().deinit(); } }
- SSHDevice.javaという名前のファイルを作成します。 SSHDevice.javaファイルには、RRPCコマンドを受信するために使用されるメインメソッドが含まれています。
SSHShell
を呼び出してSSHコマンドを実行し、RRPC応答を返すこともできます。 SSHDevice.javaファイルに、デバイス証明書情報とSSHユーザー名とパスワードを入力する必要があります。 デバイス証明書情報には、ProductKey、DeviceName、およびDeviceSecretが含まれます。パブリッククラスSSHDevice { // =================== 必要なパラメーターを設定するセグメントの先頭。 // プロダクトのProductKey。 private static String productKey = ""; // private static String deviceName = ""; // デバイスのDeviceSecret。 private static String deviceSecret = ""; // メッセージングに使用するトピック。 トピックを作成または定義する必要なく、トピックを使用できます。 プライベート静的文字列rrpcTopic = "/sys/" + productKey + "/" + deviceName + "/rrpc/request/+"; // SSHクライアントがアクセスする必要があるエンドポイントまたはIPアドレス。 プライベート静的文字列ホスト="127.0.0.1"; // SSHクライアントへのログインに使用されるユーザー名。 プライベート静的文字列username = ""; // ユーザー名のパスワード。 プライベート静的String password = ""; // SSHクライアントへのログインに使用されるポートの番号。 プライベート静的int port = 22; // =================== 必要なパラメーターを設定するセグメントの終わり。 public static void main(String[] args) throws InterruptedException { // ダウンストリームデータをリッスンします。 registerNotifyListener(); // 接続を確立します。 Device.connect(productKey、deviceName、deviceSecret); // トピックを購読します。 Device.subscribe(rrpcTopic); } public static void registerNotifyListener() { LinkKit.getInstance().registerOnNotifyListener(new IConnectNotifyListener() { @オーバーライド public boolean shouldHandle(String connectId, String topic) { // 特定のトピックからのメッセージのみを処理します。 if (topic.contains("/rrpc/request/")) { return true; } else { return false; } } @オーバーライド public void onNotify(String connectId, String topic, AMessage aMessage) { // RRPC要求を受信し、RRPC応答を返します。 try { // リモートコマンドを実行します。 String payload = new String((byte[]) aMessage.getData(), "UTF-8"); SSHShell sshExecutor=新しいSSHShell (ホスト、ユーザー名、パスワード、ポート); sshExecutor.exeかわいい (ペイロード); // コマンドの出力を取得します。 StringBuffer sb=新しいStringBuffer(); ベクトル <String> stdout = sshExecutor.getStdout(); for (String str : stdout) { sb.append(str); sb.append("\n"); } // 出力をサーバーに返します。 文字列レスポンス=topic.replace("/request/", "/response/"); Device.publish(response, sb.toString()); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } @オーバーライド public void onConnectStateChange(String connectId, ConnectState connectState) { } }); } }
IoT Platform SDKの開発
IoT Platform SDKをインストールしてサンプルコードをダウンロードしたら、プロジェクトの依存関係と必要なJavaファイルを追加します。
- 次の依存関係をpom.xmlファイルに追加します。重要 IoT Platform SDKの最新バージョンの詳細については、「IoT Platform SDK For Javaの使用」をご参照ください。
<! -- IoTプラットフォーム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>
- OpenApiClient.javaという名前のファイルを作成して、IoT Platform API操作を呼び出します。
パブリッククラスOpenApiClient { プライベート静的DefaultAcsClientクライアント=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 !! 例外: "+ e.getMessage(); } return client; } }
- SSHCommandSender.javaという名前のファイルを作成します。 SSHCommandSender.javaファイルには、SSHコマンドの送信およびSSHコマンドに対する応答の受信に使用されるメインメソッドが含まれています。 SSHCommandSender.javaファイルで、デバイス証明書情報、Alibaba CloudアカウントのAccessKeyペア、およびSSHコマンドを指定する必要があります。 デバイス証明書情報には、ProductKey、DeviceName、およびDeviceSecretが含まれます。
パブリッククラスSSHCommandSender { // =================== 必要なパラメーターを設定するセグメントの先頭。 // Alibaba CloudアカウントのAccessKey ID。 プライベート静的文字列accessKeyID = ""; // Alibaba CloudアカウントのAccessKeyシークレット。 private static String accessKeySecret = ""; // プロダクトのProductKey。 private static String productKey = ""; // デバイスのDeviceName。 private static String deviceName = ""; // =================== 必要なパラメーターを設定するセグメントの終わり。 public static void main(String[] args) throws ServerException, ClientException, UnsupportedEncodingException { // リモートLinuxコマンド。 String payload = "uname -a"; // RRPCリクエストを作成します。 RRpcRequest request = new RRpcRequest(); request.setProductKey(productKey); request.setDeviceName(deviceName); request.setRequestBase64Byte(Base64.encodeBase64String(payload.getBytes())); request.setTimeout(5000); // サーバーからリクエストを受信するために使用されるクライアント。 DefaultAcsClientクライアント=OpenApiClient.getClient(accessKeyID、accessKeySecret); // RRPCリクエストを送信します。 RRpcResponse response = (RRpcResponse) client.getAcsResponse(request); // RRPC応答を処理します。 // response.getSuccess() 関数の実行後に返される結果は、RRPC要求が送信されたことのみを示します。 返された応答は、要求がデバイスによって受信されたかどうか、またはデバイスが結果に基づいて応答を返したかどうかを示さない。 // 返されたRRPC応答コードに基づいて結果を確認する必要があります。 詳細については、「https://www.alibabacloud.com/help/doc-detail/69797.htm. 」をご参照ください。 if (response != null && "SUCCESS".equals(response.getRrpcCode())) { // 出力。 System.out.println (新しい文字列 (Base64.decodeBase64(response.getPayloadBase64Byte()) 、"UTF-8")); } else { // 出力を取得し、関連するRRPC応答コードを印刷できませんでした。 System.out.println(response.getRrpcCode()); } } }