Node.js socketaddress.port エラーとトラブルシューティング完全ガイド (日本語)

2025-05-01

より具体的に説明すると、以下のようになります。

  • クライアントサイド (Client-side): クライアントがリモートサーバーに接続する際に、接続先のサーバーが使用しているポート番号を示します。例えば、クライアントが example.com のポート443(HTTPS)に接続する場合、接続が確立されたソケットアドレスオブジェクトの port プロパティは 443 になります。
  • サーバーサイド (Server-side): サーバーがクライアントからの接続を待ち受ける特定のポート番号を示します。例えば、HTTPサーバーがポート80でリッスンしている場合、そのサーバーのソケットアドレスオブジェクトの port プロパティは 80 になります。

Node.jsの net モジュールや dgram モジュールなど、ネットワーク関連のモジュールでソケットが作成されると、そのソケットに関連付けられたアドレス情報(IPアドレスやポート番号など)を含むオブジェクトが生成されることがあります。このオブジェクトが socketaddress と呼ばれるもので、その中の port プロパティにポート番号が格納されています。

例えば、サーバーがリッスンしているポート番号を取得する一般的な方法は以下のようになります。

const net = require('net');

const server = net.createServer((socket) => {
  // クライアントとの接続処理
});

server.listen(3000, '127.0.0.1', () => {
  const address = server.address();
  console.log(`サーバーはポート ${address.port} でリッスンしています。`);
});

この例では、server.address() メソッドを呼び出すことで、サーバーがリッスンしているアドレス情報を含むオブジェクトを取得し、そのオブジェクトの port プロパティにポート番号 3000 が格納されています。

同様に、クライアントソケットで接続先のポート番号を取得する場合も、ソケットオブジェクトのアドレス情報を参照することで socketaddress.port の値を取得できます。



以下に、よくあるエラーとそのトラブルシューティング方法を挙げます。

アドレスが使用中 (Address already in use - EADDRINUSE)

  • トラブルシューティング
    • 使用中のプロセスを特定
      ターミナルで以下のコマンドを実行して、指定したポートを使用しているプロセスを特定します。
      • macOS/Linux
        sudo lsof -i :<ポート番号> または netstat -nap | grep <ポート番号>
      • Windows
        netstat -ano | findstr "<ポート番号>"
    • プロセスの終了
      特定されたプロセスのプロセスID (PID) を使用して、プロセスを終了します。
      • macOS/Linux
        kill <PID> (強制終了する場合は kill -9 <PID>)
      • Windows
        taskkill /F /PID <PID>
    • 別のポートを使用
      問題のポートがどうしても使用できない場合は、別の空いているポート番号を使用するようにサーバーの設定を変更します。
    • サーバー終了処理の確認
      サーバーが終了する際に、ソケットを適切にクローズする処理が実装されているか確認します。
  • 原因
    • 別のNode.jsサーバーや他のアプリケーションが同じポートで実行されている。
    • 以前に起動したサーバープロセスが正常に終了せず、ポートを解放していない。
  • エラー内容
    サーバーを起動しようとした際に、指定したポート番号がすでに別のプロセスによって使用されている場合に発生します。

許可が拒否されました (Permission denied - EACCES)

  • トラブルシューティング
    • 1024番以上のポートを使用
      特権を必要としない1024番以上のポート番号を使用するようにサーバーの設定を変更します。
    • 管理者権限で実行
      サーバーを起動する際に、管理者権限(root権限)で実行します(推奨されません。セキュリティリスクが高まります)。通常はリバースプロキシ(Nginx, Apacheなど)を使用して、80番や443番ポートへのアクセスを、高ポートで動作するNode.jsアプリケーションに転送する構成が一般的です。
  • 原因
    • 一般ユーザー権限で、root権限が必要なポート番号を使用しようとしている。
  • エラー内容
    特権が必要なポート番号(通常は1024番以下のポート)でサーバーを起動しようとした場合に、適切な権限がないと発生します。

指定されたホストへのルートがない (Cannot assign requested address - EADDRNOTAVAIL)

  • トラブルシューティング
    • 正しいIPアドレスを確認
      ipconfig (Windows) や ifconfig (macOS/Linux) コマンドを使用して、サーバーマシンのネットワークインターフェースに割り当てられているIPアドレスを確認し、server.listen() に正しいIPアドレスを指定します。
    • ワイルドカードアドレス (0.0.0.0) の使用
      全ての利用可能なネットワークインターフェースでリッスンする場合は、IPアドレスに '0.0.0.0' を指定します。
  • 原因
    • 存在しないIPアドレスや、ネットワークインターフェースに設定されていないIPアドレスを指定している。
  • エラー内容
    server.listen() などで指定したIPアドレスが、サーバーが動作しているマシンに割り当てられていない場合に発生します。

ファイアウォールによる接続拒否

  • トラブルシューティング
    • ファイアウォールの設定確認
      サーバーおよびクライアント側のファイアウォールの設定を確認し、使用しているポート番号に対するトラフィックが許可されているか確認します。
    • ポートの開放
      必要に応じて、ファイアウォールで該当のポートを開放します。
  • 原因
    • サーバーがリッスンしているポートが、サーバーまたはクライアント側のファイアウォールで受信または送信が許可されていない。
  • エラー内容
    クライアントからの接続がサーバーに到達できない場合、ファイアウォールが特定のポートへのアクセスをブロックしている可能性があります。

クライアント側のポート指定ミス

  • トラブルシューティング
    • クライアントコードの確認
      クライアント側の接続処理で、正しいポート番号が使用されているか確認します。サーバー側の socketaddress.port の値と一致している必要があります。
  • 原因
    • クライアントコードで、サーバーがリッスンしているポート番号とは異なるポート番号を指定している。
  • エラー内容
    クライアントがサーバーに接続する際に、誤ったポート番号を指定している場合、接続エラーが発生します。

socketaddress.port をトラブルシューティングに役立てる方法

エラーが発生した場合、サーバーやクライアントのソケットオブジェクトから address() メソッドを呼び出すことで、現在関連付けられているアドレス情報(IPアドレスとポート番号)を取得できます。この address().port の値を確認することで、実際にどのポートで通信を試みているのかを把握し、設定ミスやポートの競合などの原因を特定するのに役立ちます。

例えば、サーバーが意図しないポートでリッスンしている場合や、クライアントが誤ったポートに接続しようとしている場合などに、 socketaddress.port の値を確認することで問題に気づくことができます。



例1: サーバーがリッスンしているポート番号を取得する

この例では、Node.jsの net モジュールを使用して簡単なTCPサーバーを作成し、サーバーがリッスンを開始した後に、そのポート番号を取得して表示します。

const net = require('net');

const server = net.createServer((socket) => {
  console.log('クライアントが接続しました。');

  socket.on('end', () => {
    console.log('クライアントが切断しました。');
  });

  socket.write('サーバーからのメッセージです。\r\n');
  socket.pipe(socket); // エコーバック
});

const PORT = 3000;
const HOST = '127.0.0.1';

server.listen(PORT, HOST, () => {
  const address = server.address();
  console.log(`サーバーは ${address.address}:${address.port} でリッスンを開始しました。`);
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
});

このコードでは、server.listen(PORT, HOST, callback) でサーバーを指定されたポートとIPアドレスで起動しています。コールバック関数の中で server.address() を呼び出すと、サーバーのアドレス情報(IPアドレスとポート番号)を含むオブジェクトが返されます。このオブジェクトの port プロパティに、実際にサーバーがリッスンしているポート番号が格納されています。

例2: クライアントが接続したサーバーのポート番号を取得する

この例では、クライアントがサーバーに接続した際に、接続先のサーバーのポート番号を取得して表示します。

const net = require('net');

const client = net.createConnection({ port: 3000, host: '127.0.0.1' }, () => {
  console.log('サーバーに接続しました。');
  const address = client.remoteAddress;
  const port = client.remotePort;
  console.log(`接続先のサーバーアドレス: ${address}:${port}`);

  client.write('クライアントからのメッセージです。\r\n');
});

client.on('data', (data) => {
  console.log('サーバーからのデータ:', data.toString());
  client.end();
});

client.on('end', () => {
  console.log('サーバーとの接続を終了しました。');
});

client.on('error', (err) => {
  console.error('クライアントエラー:', err);
});

このコードでは、net.createConnection() を使用してサーバーに接続しています。接続が確立されると、クライアントソケットオブジェクトの remoteAddress プロパティに接続先のIPアドレス、remotePort プロパティに接続先のポート番号が格納されます。これらを使用して、接続先のサーバーのアドレスとポート番号を表示しています。

例3: UDPソケットで送信元と宛先のポート番号を確認する

この例では、dgram モジュールを使用してUDPソケットを作成し、メッセージを送信する際に送信元と宛先のポート番号を確認します。

const dgram = require('dgram');

// サーバー (受信側)
const server = dgram.createSocket('udp4');

server.on('message', (msg, rinfo) => {
  console.log(`サーバーは ${rinfo.address}:${rinfo.port} からメッセージを受信しました: ${msg.toString()}`);
});

server.on('listening', () => {
  const address = server.address();
  console.log(`UDPサーバーは ${address.address}:${address.port} でリッスンを開始しました。`);
});

server.bind(41234);

// クライアント (送信側)
const client = dgram.createSocket('udp4');
const message = Buffer.from('UDPメッセージを送信します。');
const serverPort = 41234;
const serverAddress = '127.0.0.1';

client.send(message, serverPort, serverAddress, (err) => {
  if (err) {
    console.error('メッセージ送信エラー:', err);
    client.close();
    server.close();
    return;
  }
  const clientAddress = client.address();
  console.log(`クライアントはポート ${clientAddress.port} から ${serverAddress}:${serverPort} へメッセージを送信しました。`);
  client.close();
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
  server.close();
  client.close();
});

この例では、UDPサーバーがポート 41234 でリッスンを開始し、クライアントが同じポート番号とIPアドレスにメッセージを送信しています。サーバー側の message イベントリスナーの rinfo オブジェクトには、送信元のIPアドレス (rinfo.address) とポート番号 (rinfo.port) が含まれています。クライアント側では、client.address() を呼び出すことで、クライアント自身のソケットのアドレス情報(ポート番号など)を取得できます。



環境変数を利用したポート番号の設定

アプリケーションの起動時に、環境変数を通じてポート番号を設定する方法です。これにより、設定ファイルを変更せずにデプロイ環境に合わせてポート番号を柔軟に変更できます。

const net = require('net');

const DEFAULT_PORT = 3000;
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : DEFAULT_PORT;
const HOST = '127.0.0.1';

const server = net.createServer((socket) => {
  console.log('クライアントが接続しました。');
  socket.end('Hello, client!\n');
});

server.listen(PORT, HOST, () => {
  const address = server.address();
  console.log(`サーバーはポート ${address.port} でリッスンを開始しました。`);
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
});

この例では、process.env.PORT 環境変数が設定されていればその値を使用し、そうでなければデフォルトのポート番号 (3000) を使用しています。このようにして設定されたポート番号は、server.listen() に渡され、実際にサーバーがリッスンするポートとなります。server.address().port を使用して、最終的に使用されたポート番号を確認できます。

設定ファイルからのポート番号の読み込み

JSONやYAMLなどの設定ファイルにポート番号を記述し、アプリケーションの起動時に読み込んで使用する方法です。これにより、ポート番号だけでなく、他の設定情報も一元的に管理できます。

const net = require('net');
const fs = require('fs');
const path = require('path');

const configPath = path.join(__dirname, 'config.json');
let config;

try {
  const configFile = fs.readFileSync(configPath, 'utf8');
  config = JSON.parse(configFile);
} catch (err) {
  console.error('設定ファイルの読み込みに失敗しました:', err);
  process.exit(1);
}

const PORT = config.port || 3000;
const HOST = config.host || '127.0.0.1';

const server = net.createServer((socket) => {
  console.log('クライアントが接続しました。');
  socket.end('Hello from config!\n');
});

server.listen(PORT, HOST, () => {
  const address = server.address();
  console.log(`サーバーはポート ${address.port} でリッスンを開始しました。`);
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
});

config.json ファイルの例:

{
  "port": 8080,
  "host": "0.0.0.0"
}

この例では、fs モジュールを使用して config.json ファイルを読み込み、その中の port プロパティをサーバーのポート番号として使用しています。

コマンドライン引数からのポート番号の指定

アプリケーションの起動時に、コマンドライン引数としてポート番号を指定する方法です。一時的に異なるポートでテストしたい場合などに便利です。

const net = require('net');

const args = process.argv.slice(2);
const portArg = args.find(arg => arg.startsWith('--port='));
const PORT = portArg ? parseInt(portArg.split('=')[1], 10) : 3000;
const HOST = '127.0.0.1';

const server = net.createServer((socket) => {
  console.log('クライアントが接続しました。');
  socket.end(`Hello from port ${PORT}!\n`);
});

server.listen(PORT, HOST, () => {
  const address = server.address();
  console.log(`サーバーはポート ${address.port} でリッスンを開始しました。`);
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
});

このスクリプトは、例えば node server.js --port=8888 のように実行することで、ポート番号 8888 でサーバーを起動できます。

ポート番号の自動割り当て (ポート 0 の利用)

server.listen() にポート番号として 0 を指定すると、オペレーティングシステムが利用可能なポートを自動的に割り当てます。これは、特定のポート番号に依存しないテスト環境などで役立ちます。割り当てられたポート番号は、server.address().port を呼び出すことで確認できます。

const net = require('net');

const server = net.createServer((socket) => {
  console.log('クライアントが接続しました。');
  socket.end('Hello from auto-assigned port!\n');
});

server.listen(0, '127.0.0.1', () => {
  const address = server.address();
  console.log(`サーバーは自動割り当てされたポート ${address.port} でリッスンを開始しました。`);
});

server.on('error', (err) => {
  console.error('サーバーエラー:', err);
});