はじめてのプロセス間通信

## はじめに

「Node.js入門」を少し読みましたので、そのことを少し書きます。基本的なことはネットで見つけることができますので、この記事では「9.4 TCPエコーサーバ・クライアントの実装」のサンプルコードを少し変更して、クライアント間でデータを送受信できるか試してみたことを紹介します。流れとしては、ソースコードを紹介して、試し方を紹介して、試してみた感想になります。

必要なファイルは二つです。`server.js`と`client.js`です。（テキストで紹介されているファイル名とは違うファイル名です。）

## サーバ側（常駐プロセス）

ソースコードのみの紹介になります。

```js
var net = require('net');

var server = net.createServer();
server.maxConnections = 3;

function Client(socket) {
  this.socket = socket;
}

Client.prototype.writeData = function(d) {
  var socket = this.socket;
  if (socket.writable) {
    var key = socket.remoteAddress + ':' + socket.remotePort;
    process.stdout.write('[' + key + '] - ' + d);
    socket.write('[R] ' + d);
  }
};

var clients = {};

function chomp(raw_text)
{
  return raw_text.replace(/(\n|\r)+$/,'');
}

server.on('connection', function(socket) {
  var status = server.connections + '/' + server.maxConnections;
  var key = socket.remoteAddress + ':' + socket.remotePort;
  console.log('Connection Start(' + status + ') - ' + key);
  clients[key] = new Client(socket);

  var data = '';
  var newline = /\r\n|\n/;
  socket.on('data', function(chunk) {
    var k = chunk.toString();
    if (newline.test(k)) {
      k = chomp(k);
      clients['127.0.0.1:' + k].writeData('test data\n');
      k ='';
    }
  });

  socket.on('end', function(socket) {
    console.log('Connection End(' + status + ') - ' + key);
    delete clients[key];
  });
});

server.on('close', function() {
  console.log('Server Closed');
});

process.on('SIGINT', function() {
  for (var i in clients) {
    var socket = clients[i].socket;
    socket.end();
  }
  server.close();
});

server.on('listening', function() {
  var addr = server.address();
  console.log('Listening Start on Server - ' + addr.address + ':' + addr.port);
});

server.listen(11111, '127.0.0.1');
// vim: set sw=2 sts=2 et :
```

## クライアント側（非常駐プロセス）

こちらもソースコードのみの紹介になります。

```js
var net = require('net');

var options = {};
options.host = process.argv[2];
options.port = process.argv[3];

var client = net.connect(options);

client.on('error', function(e) {
  console.error('Connection Failed - ' + options.host + ':' + options.port);
  console.error(e.message);
});

client.on('connect', function() {
  console.log('Connection - ' + options.host + ':' + options.port);
});

process.on('SIGINT', function() {
  console.log('Connction Closed - ' + options.host + ':' + options.port);
  client.end();
});

process.stdin.on('data', function(data) {
  process.stdout.write('[S] ' + data);
  client.write(data);
});

client.on('data', function(chunk) {
  process.stdout.write(chunk.toString());
});

client.on('end', function(had_error) {
  console.log('Connction End - ' + options.host + ':' + options.port);
});

client.on('close', function() {
  console.log('Client Closed');
  process.exit(0);
});
```

## 試し方

ターミナルが三つ必要になります。

まず、一つ目のターミナルでサーバを起動します。

```
$ node server.js
```

次に、二つ目のターミナルでクライアントからサーバに接続します。第2引数にサーバのIPアドレス、第3引数にサーバのポート番号を指定します。

```
$ node client.js 127.0.0.1 11111
```

クライアント間でデータを送受信させたいので、もう一つクライアントが必要です。なので、三つ目のターミナルでもクライアントからサーバに接続します。

```
$ node client.js 127.0.0.1 11111
```

この段階で一つ目のターミナルを確認すると、二つ目のターミナルのクライアントのポート番号と三つ目のターミナルのクライアントのポート番号を確認できます。

```
Connection Start(1/3) - 127.0.0.1:49238
Connection Start(2/3) - 127.0.0.1:49239
```

さて、いよいよです。

一方のクライアントでもう一方のクライアントのポート番号を入力してみましょう。

```
49239
```

もう一方のクライアントを確認してみましょう。

```
[R] test data
```

クライアント間でデータを送受信できました。

## まとめ

呆れた顔が目に浮かびます。いまどきのSocket.IOを使えばチャットを実装できるそうです。そういう技術がそろっている時代に、このような実装に挑戦して意味があるのでしょうか？そういう疑問もあるかもしれませんが、できそうだと思ったら、試してみたくなってしまったのです。

試してみて気付いたことはいくつかあります。一つは、サーバ側にクライアント間の通信用のプロトコルを実装すれば、もう少しマシな通信が実装できそうだということ。もう一つは、複数の機械を制御するためには、プロセス間通信みたいな仕組みが必要そうだということ。ちょっとした気付きでしたが、有意義な経験だったと思います。