Node.jsを使ったECS上でのTCPアプリケーションの構築

このチュートリアルでは、**Alibaba Cloud** ECSを使って**TCP**クライアント/サーバのペアを作成し、**Node.js**を使って**TCP**アプリケーションを構築していきます。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/node-js-tcp-app-development-on-ecs_594176)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

Alibaba Cloud Tech Share執筆者のKunal Relanによるものです。Tech Shareは、クラウドコミュニティ内で技術的な知識やベストプラクティスを共有することを奨励するAlibaba Cloudのインセンティブプログラムです。

まず基本的なことから説明すると、オープンソースのJavaScriptランタイム環境として人気のあるものに、ChromeのV8 JavaScriptエンジン上に構築されたNode.jsがあります。Node.jsは主にサーバーサイドやネットワークアプリケーションの構築に使われています。TCP (Transmission Control Protocol) は、アプリケーション間でデータのストリームを信頼性の高い、順序立てられた、エラーチェックされた配信を可能にするネットワーキングプロトコルです。双方がデータストリームを交換するためには、TCPサーバがTCP接続要求を受け入れ、接続が確立されなければなりません。

TCP ソケットプログラムには、サーバとクライアントの 2 種類のプログラムを書くことができます。サーバの機能は、クライアントからの接続をリッスンし、処理されたデータを送り返すことです。この通信はソケットを介して行われます。

node.jsのTCPプログラミングにはnetという内部モジュールが必要で、ネットワークプログラミングの非同期ラッパーとして機能します。サーバとクライアントの構築にはAlibaba Cloud Elastic Compute Service (ECS)を使用します。

#はじめに
このチュートリアルに従うためには、ubuntuやmacOSなどのlinux/unixディストリビューションが動作するマシン、コードエディタ/IDEのnode.jsがインストールされていること、node.jsの基本的な知識が必要です。このチュートリアルでは、アプリケーションを本番環境にデプロイするのではなく、開発用のマシンで実行し、そこからテストを行います。

#TCPサーバの作成
まず、アプリケーションを保存するディレクトリを作成します。このチュートリアルでは、`~/nodejs-tcp-app`にアプリケーションを作成します。

このチュートリアルでは、ほとんどの作業をターミナルで行います。また、ターミナルで`nano`エディタを使用して、すべてのプラットフォームで同じプロセスを保証します。

開始するには、ターミナルを開きます。

```
mkdir ~/nodejs-tcp-app
```

さて、新しく作成したディレクトリに切り替えて、`npm init`を実行してpackage.jsonファイルを作成します。

```
cd ~/nodejs-tcp-app && npm init
```

これでターミナルからプロジェクトの基本情報を聞かれるので、`server.js`として名前、作者、メインファイルを追加してファイルを作成します。これでディレクトリ内に`package.json`ファイルが表示されるはずです。

次に、TCPサーバのコードを含む`server.js`ファイルを作成します。

同じディレクトリに以下のコマンドを入力して、`server.js`ファイルを作成し、テキストエディタを開いてコードを書きます。

```
nano server.js
```

まず、node.jsに同梱されている`net`モジュールをインポートし、サーバーを実行するポートとホストを定義して、サーバーのインスタンスを作成します。

```
const net = require('net');
//define host and port to run the server
const port = 8080;
const host = '127.0.0.1';

//Create an instance of the server
const server = net.createServer();
//Start listening with the server on given port and host.
server.listen(port,host,function(){
   console.log(`Server started on ${host}:${port}`); 
});
```

これはアプリケーションの基本的な構成要素であり、TCP サーバを起動するのに十分なものです。

次に、クライアントが接続する接続にリスナーを追加する必要があります。

サーバの宣言を編集して、`onClientConnection`という接続リスナー関数を追加し、下部に関数を宣言します。

```
const net = require('net');
//define host and port to run the server
const port = 8080;
const host = '127.0.0.1';

//Create an instance of the server
const server = net.createServer(onClientConnection);
//Start listening with the server on given port and host.
server.listen(port,host,function(){
   console.log(`Server started on port ${port} at ${host}`); 
});

//Declare connection listener function
function onClientConnection(sock){
    //Log when a client connnects.
    console.log(`${sock.remoteAddress}:${sock.remotePort} Connected`);
     //Listen for data from the connected client.
    sock.on('data',function(data){
        //Log data from the client
        console.log(`${sock.remoteAddress}:${sock.remotePort} Says : ${data} `);
        //Send back the data to the client.
        sock.write(`You Said ${data}`);
    });
    //Handle client connection termination.
    sock.on('close',function(){
        console.log(`${sock.remoteAddress}:${sock.remotePort} Terminated the connection`);
    });
    //Handle Client connection error.
    sock.on('error',function(error){
        console.error(`${sock.remoteAddress}:${sock.remotePort} Connection Error ${error}`);
    });
};
```

そこで、onClientConnection関数では、接続オブジェクトの`sock`を期待して、`data`、`close`、`error`の3つのイベントリスナーを作成します。

データイベントリスナーでは、クライアントから受信した`data`をコンソールログに記録してクライアントに送信し、`close`イベントリスナーでは、接続の終了を処理してコンソールログに記録します。`error`イベントリスナーはクライアントからの接続エラーを処理します。

これで `server.js` のコードが完成し、これで TCP クライアントの接続を受け入れ、それらのデータをリッスンしてクライアントにエコーバックする TCP アプリケーションが動作するようになりました。ファイルを保存してnanoエディタを終了します。

同じモジュールを使って TCP クライアントを作成してみましょう。

#TCP クライアントの作成
nanoコマンドを使って`client.js`ファイルを作成し、作業を開始してみましょう。

```
nano client.js
```

`server.js`でやったように、netモジュールをインポートして引数を定義してみましょう。

```
const net = require('net');
//define the server port and host
const port = 8080;
const host = '127.0.0.1';
//Create an instance of the socket client.
const client = new net.Socket();
//Connect to the server using the above defined config.
client.connect(port,host,function(){
   console.log(`Connected to server on ${host}:${port}`);
   //Connection was established, now send a message to the server.
   client.write('Hello from TCP client');
});
//Add a data event listener to handle data coming from the server
client.on('data',function(data){
   console.log(`Server Says : ${data}`); 
});
//Add Client Close function
client.on('close',function(){
   console.log('Connection Closed');
});
//Add Error Event Listener
client.on('error',function(error){
   console.error(`Connection Error ${error}`); 
});
```

これで`client.js`はサーバーに接続し、接続時にメッセージを送信し、サーバーからのレスポンスをログに記録します。

ここでもサーバと同様に、データ、接続終了、接続エラーを処理するための3つのイベントリスナーを追加しています。

ファイルを保存して`nano`エディタを終了します。

#接続のテスト
TCPベースのサーバとクライアントアプリの作成が完了したので、サーバを起動してTCPクライアントをサーバに接続する必要があります。

このためには、2つのターミナルセッションが必要です-1つはサーバ用、もう1つはクライアント用です。

最初のセッションでは、次のコマンドを使用してサーバを起動します。

```
node server.js
```

このコマンドはTCPサーバを起動し、ターミナルにログが表示されるはずです。

```
Server started on 127.0.0.1:8080
```

次に、サーバーに接続してメッセージを送信するためにTCPクライアントファイルを起動する必要があります。別のターミナルで次のコマンドを入力します。

```
node client.js
```

これでTCPクライアントが起動し、サーバに接続してメッセージを送信しようとします。さて、あなたのターミナルには次のようなテキストが表示されているはずです。

```
Connected to server on 127.0.0.1:8080
Server Says : You Said Hello from TCP client
```

これで、クライアントがサーバに接続できて、ログを記録できるエコーを受信したことがわかりました。

次に、サーバを実行しているターミナルセッションに戻ると、このように表示されるはずです。ただし、クライアントのポートは異なる場合があります。

```
127.0.0.1:56330 Connected
127.0.0.1:56330 Says : Hello from TCP client 
```

プログラムでクライアント接続を閉じるわけではないので、close イベントリスナーはトリガーされません。しかし、クライアント端末に戻って ^c を押すと、クライアントは終了し、サーバ端末では接続終了のログを取得することができます。

```
127.0.0.1:56330 Terminated the connection
```

TCPサーバとクライアントのテストに成功しました。

#結論
このチュートリアルでは、Alibaba Cloud Elastic Compute Service (ECS)インスタンス上でNode.jsを使ってTCPアプリケーションを作成しました。TCPソケットを使ってもっと多くのことができますが、これはその入門的なプログラムでした。これの高度なバージョンでは、TCPサーバを介してメッセージの送受信を可能にするチャットルームにすることができます。また、リアルタイムのデータ通信のための大きなデータストリームの塊を処理するために使用することもできます。

*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*