1台のPCで大量の接続テストをしたい

# ミッション

1000台分の接続テストがしたい。

# 下準備
Linuxのシェルスクリプトで
[一枚のNICに大量のIPアドレスを割り当てる](http://qiita.com/kenji-yokoi/items/768178ee31153be7a552)
Windowsのバッチファイルで
[一枚のNICに大量のIPアドレスを割り当てる(Windowsバッチ編)](http://qiita.com/kenji-yokoi/items/ac9d5bcb2fbc9f89005b)

# 実装

とある内製サーバーアプリケーションのテストで多数の接続テストがしたい。
でも、そんなにクライアントを用意できないので、仮想クライアントを用意しようというのが始まりです。
一枚のNICに大量のIPアドレスを割り付けて、複数のIPアドレスから繋いでいる風にみせようかと。
とりあえずNode.jsでサーバーとクライアントのアプリのサンプルを作って見ました。

サーバーは待ち受けてエコーしているだけです。

```js:server.js
var net = require('net');
var readline = require('readline');
require('date-utils');

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

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

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

function log(log) {
  var date = new Date();
  var formatted = date.toFormat("YYYY/MM/DD HH24:MI:SS");
  process.stdout.write( formatted + ":" + log + '\r\n');
}

var clients = {}

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

server.on('connection', function(socket){
  var data = '';
  var newline = /\r\n|\n/;
  socket.on('data', function(chunk){
    data += chunk.toString();
    var key = socket.remoteAddress + ':' + socket.remotePort;
    if(newline.test(data)){
      clients[key].writeData(data);
      data = '';
    }
  });
});

server.on('connection', function(socket){
  var key = socket.remoteAddress + ':' + socket.remotePort;
  socket.on('end', function(){
    var status = server.connections + '/' + server.maxConnections;
    log('Connection End(' + status + ') - ' + key);
    delete clients[key];
  });
});

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

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

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

クライアントはlocalAddressを変えながら繋いでいます。

```js:client.js
var net = require('net');
require('date-utils');

function log(log) {
  var date = new Date();
  var formatted = date.toFormat("YYYY/MM/DD HH24:MI:SS");
  process.stdout.write( formatted + ":" + log + '\r\n');
}

var adr3Array=[], adr4Array=[];
for(var i=40; adr3Array.push(i++) < 50;);
for(var j=0; adr4Array.push(j++) < 100;);

function clientFunc(local) {
  var options = {
    port: 8778,
    host: '172.21.0.228',
    localAddress: local
  };
  var client = net.connect(options);
  client.on('error', function(e){
    log(local + ':Connection Failed');
    log(e.message);
  });
  
  client.on('connect', function(){
    log(local + ':Connected');
  });
  
  client.setTimeout(1000);
  client.on('timeout', function(){
    var str = 'Hello World\r\n';
    log(local + ":" + str);
    client.write(str);
  });
  
  client.on('data', function(chunk){
    log(local + ":" + chunk.toString());
  });
  
  client.on('end', function(had_error){
    client.setTimeout(0);
    log(local + ':Connetion End');
  });
  
  client.on('close', function(){
    log(local + ':Client Closed');
  });
};


adr3Array.forEach(function(adr3) {
  adr4Array.forEach(function(adr4) {
    clientFunc('172.21.'+adr3+'.'+adr4);
  });
});
```

# 確認

サーバー側のログ。

```
2016/04/29 13:28:58:[172.21.47.28:59911] - Hello World
2016/04/29 13:28:58:[172.21.47.29:59912] - Hello World
2016/04/29 13:28:58:[172.21.47.30:59913] - Hello World
2016/04/29 13:28:58:[172.21.47.31:59914] - Hello World
2016/04/29 13:28:58:[172.21.47.32:59915] - Hello World
2016/04/29 13:28:58:[172.21.47.33:59916] - Hello World
2016/04/29 13:28:58:[172.21.47.34:59917] - Hello World
2016/04/29 13:28:58:[172.21.47.35:59918] - Hello World
2016/04/29 13:28:58:[172.21.47.36:59919] - Hello World
2016/04/29 13:28:58:[172.21.47.37:59920] - Hello World
```

あとはクライアント側の実装を、実際のサーバーの電文仕様に合わせていこう。
それが大変なわけだが・・・。