Node.js ネットワークプログラミング入門:net.SocketAddress の基礎と応用
net.SocketAddressとは?
"net.SocketAddress"は、Node.jsの"net"モジュールで提供されるクラスであり、ネットワークソケットのアドレス情報を表現するために使用されます。具体的には、IPアドレス、ポート番号、およびアドレスファミリー(IPv4またはIPv6)を保持します。
主な用途
"net.SocketAddress"は、主に以下の場面で使用されます。
- ソケットアドレス情報の比較
2つのソケットアドレスが同じかどうかを比較するために使用されます。 - ソケットアドレス情報の表示
ソケット接続のデバッグやログ記録時に、接続先のIPアドレスやポート番号を表示するために使用されます。 - ソケットアドレス情報の取得
"net.Socket"オブジェクトの"remoteAddress"、"remotePort"、"localAddress"、"localPort"などのプロパティから取得される情報が、"net.SocketAddress"オブジェクトとして返されます。
プロパティ
"net.SocketAddress"オブジェクトには、以下のプロパティがあります。
port
: ポート番号(整数)。例:8080
。family
: アドレスファミリー(文字列)。"IPv4"
または"IPv6"
。address
: IPアドレス(文字列)。例:"127.0.0.1"
、"::1"
。
例
以下は、Node.jsで"net.SocketAddress"を使用する簡単な例です。
const net = require('net');
const server = net.createServer((socket) => {
console.log('クライアントが接続しました。');
const remoteAddress = socket.remoteAddress;
const remotePort = socket.remotePort;
const localAddress = socket.localAddress;
const localPort = socket.localPort;
console.log('クライアントのIPアドレス:', remoteAddress);
console.log('クライアントのポート番号:', remotePort);
console.log('サーバーのIPアドレス:', localAddress);
console.log('サーバーのポート番号:', localPort);
console.log("リモートアドレスのオブジェクト");
console.log(socket.remoteAddress);
console.log(socket.remoteFamily);
console.log(socket.remotePort);
socket.end('接続を終了します。\n');
});
server.listen(3000, () => {
console.log('サーバーがポート3000で起動しました。');
});
この例では、クライアントがサーバーに接続した際に、クライアントとサーバーのIPアドレスとポート番号を表示しています。socket.remoteAddress、socket.remotePort、socket.localAddress、socket.localPortは内部でnet.SocketAddressのオブジェクトを返しています。
一般的なエラーとトラブルシューティング
"net.SocketAddress"クラス自体は、直接エラーを発生させるものではありません。しかし、ネットワークソケットに関連する操作で、このクラスが返す情報が期待通りでない場合や、関連するエラーが発生する場合があります。
- undefinedまたはnullが返される
- 原因
ソケットがまだ接続されていない、または接続が切断された後にremoteAddress
やremotePort
などを参照した場合に発生します。 - トラブルシューティング
- ソケットが正常に接続されているか確認します。
- ソケットイベント(
'connect'
,'close'
など)を使用して、ソケットの状態を適切に管理します。 - ソケットの接続が確立されてから情報を取得するようにコードを修正してください。
- 原因
- IPアドレスまたはポート番号が期待と異なる
- 原因
- ネットワーク設定の問題(ファイアウォール、ルーティングなど)。
- サーバーが複数のネットワークインターフェースを持っている場合に、意図しないインターフェースが選択された。
- ProxyやNATを経由している場合。
- トラブルシューティング
- ネットワーク設定を確認し、必要なポートが開放されているか、ルーティングが正しいかなどを確認します。
net.listen()
でlistenするアドレスを明示的に指定します。- ProxyやNATの構成を確認し、必要なポート転送設定などを行ってください。
- 原因
- アドレスファミリーが期待と異なる
- 原因
IPv4とIPv6の設定が混在している、または意図しないアドレスファミリーが選択された。 - トラブルシューティング
net.createConnection()
やnet.listen()
でアドレスファミリーを明示的に指定します({ family: 4 }
または{ family: 6 }
)。- OSのIPv4/IPv6の設定を確認します。
- 原因
- EADDRINUSEエラー
- 原因
指定されたポートがすでに他のプロセスで使用されている。 - トラブルシューティング
- 別のポートを使用するか、既存のプロセスを停止します。
netstat
やlsof
などのコマンドを使用して、ポートを使用しているプロセスを特定します。- サーバーを停止する前に、ソケットを適切に閉じるようにします。
- 原因
- ECONNREFUSEDエラー
- 原因
接続先のサーバーが存在しない、またはポートが閉じている。 - トラブルシューティング
- 接続先のサーバーが起動しているか、ポートが開いているかを確認します。
- IPアドレスとポート番号が正しいかを確認します。
- ファイヤーウォールが接続をブロックしていないか確認します。
- 原因
- ENOTFOUNDエラー
- 原因
指定されたホスト名をIPアドレスに解決できません。 - トラブルシューティング
- ホスト名が正しいか確認します。
- DNSサーバーの設定を確認します。
- インターネット接続を確認します。
- 原因
- Node.jsのドキュメントやコミュニティフォーラムを参照して、解決策を探します。
- エラーメッセージをよく読み、原因を特定します。
- Wiresharkなどのネットワークパケットキャプチャツールを使用して、ネットワークトラフィックを分析します。
netstat
やlsof
などのネットワークユーティリティを使用して、ネットワーク接続の状態を確認します。console.log()
を使用して、net.SocketAddress
オブジェクトの内容を詳細に表示します。
例1: サーバーのIPアドレスとポート番号を表示する
この例では、サーバーが起動した際に、サーバー自身のIPアドレスとポート番号を表示します。
const net = require('net');
const server = net.createServer((socket) => {
console.log('クライアントが接続しました。');
socket.end('接続を終了します。\n');
});
server.listen(3000, () => {
const address = server.address(); // server.address()によってnet.SocketAddressオブジェクトが返される
console.log('サーバーが', address.address, ':', address.port, 'で起動しました。');
});
解説
address.address
でIPアドレス、address.port
でポート番号を取得できます。server.address()
は、サーバーがリッスンしているアドレス情報をnet.SocketAddress
オブジェクトとして返します。
例2: クライアントのIPアドレスとポート番号を表示する
この例では、クライアントがサーバーに接続した際に、クライアントのIPアドレスとポート番号を表示します。
const net = require('net');
const server = net.createServer((socket) => {
const remoteAddress = socket.remoteAddress;
const remotePort = socket.remotePort;
const remoteFamily = socket.remoteFamily;
console.log('クライアントのIPアドレス:', remoteAddress);
console.log('クライアントのポート番号:', remotePort);
console.log('クライアントのアドレスファミリー:', remoteFamily);
socket.end('接続を終了します。\n');
});
server.listen(3000, () => {
console.log('サーバーがポート3000で起動しました。');
});
解説
- これらのプロパティは、内部で
net.SocketAddress
のプロパティから値を抽出して返します。 socket.remoteAddress
、socket.remotePort
、socket.remoteFamily
は、接続してきたクライアントのアドレス情報をそれぞれ取得します。
例3: クライアントからサーバーへ接続する
この例では、クライアントからサーバーへ接続し、接続先のIPアドレスとポート番号を表示します。
const net = require('net');
const client = net.createConnection({ port: 3000, host: '127.0.0.1' }, () => {
console.log('サーバーに接続しました。');
const localAddress = client.localAddress;
const localPort = client.localPort;
console.log('クライアントのローカルIPアドレス:', localAddress);
console.log('クライアントのローカルポート番号:', localPort);
client.end();
});
client.on('end', () => {
console.log('サーバーとの接続が終了しました。');
});
解説
client.localAddress
とclient.localPort
は、クライアント自身のローカルアドレスとポート番号を取得します。net.createConnection()
を使用してサーバーに接続します。
例4: アドレスファミリーを明示的に指定する
この例では、IPv6でサーバーを起動し、IPv6でクライアントから接続します。
const net = require('net');
const server = net.createServer((socket) => {
console.log('クライアントが接続しました。');
socket.end('接続を終了します。\n');
});
server.listen({ port: 3000, host: '::1', family: 6 }, () => {
const address = server.address();
console.log('サーバーが', address.address, ':', address.port, 'で起動しました。');
});
const client = net.createConnection({ port: 3000, host: '::1', family: 6 }, () => {
console.log('サーバーに接続しました。');
client.end();
});
host: '::1'
は、IPv6のローカルループバックアドレスを表します。server.listen()
とnet.createConnection()
でfamily: 6
を指定することで、IPv6を使用することを明示的に指定します。
- 文字列として直接IPアドレスとポート番号を扱う
net.Socket
オブジェクトのremoteAddress
、remotePort
、localAddress
、localPort
プロパティは、文字列または数値として直接IPアドレスとポート番号を提供します。net.createServer()
やnet.createConnection()
のオプションで、IPアドレスとポート番号を文字列または数値で直接指定できます。
- オブジェクトリテラルを使用する
- ソケットアドレス情報をオブジェクトリテラルで表現し、必要に応じて構造化されたデータを扱うことができます。
代替方法の例
例1: 文字列として直接IPアドレスとポート番号を扱う
const net = require('net');
const server = net.createServer((socket) => {
const remoteAddress = socket.remoteAddress;
const remotePort = socket.remotePort;
console.log(`クライアントのIPアドレス: ${remoteAddress}`);
console.log(`クライアントのポート番号: ${remotePort}`);
socket.end('接続を終了します。\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('サーバーが127.0.0.1:3000で起動しました。');
});
const client = net.createConnection(3000, '127.0.0.1', () => {
console.log('サーバーに接続しました。');
client.end();
});
解説
server.listen()
とnet.createConnection()
の引数として、ポート番号とIPアドレスを直接指定しています。socket.remoteAddress
とsocket.remotePort
は、文字列と数値でIPアドレスとポート番号を直接返します。
例2: オブジェクトリテラルを使用する
const net = require('net');
const server = net.createServer((socket) => {
const remoteAddressInfo = {
address: socket.remoteAddress,
port: socket.remotePort,
family: socket.remoteFamily,
};
console.log('クライアントのアドレス情報:', remoteAddressInfo);
socket.end('接続を終了します。\n');
});
server.listen(3000, '127.0.0.1', () => {
console.log('サーバーが127.0.0.1:3000で起動しました。');
});
解説
- これにより、構造化されたデータを扱うことができます。
- オブジェクトリテラル
remoteAddressInfo
を作成し、IPアドレス、ポート番号、アドレスファミリーを格納しています。
例3: URLオブジェクトを使用する
const url = require('url');
const addressString = 'tcp://127.0.0.1:3000';
const addressUrl = url.parse(addressString);
console.log('IPアドレス:', addressUrl.hostname);
console.log('ポート番号:', addressUrl.port);
const net = require('net');
const client = net.createConnection(addressUrl.port, addressUrl.hostname, () => {
console.log('サーバーに接続しました。');
client.end();
});
解説
- この方法を使用すると、URLに関連する他の情報(プロトコルなど)も扱うことができます。
net.createConnection()
の引数として、抽出したIPアドレスとポート番号を使用します。url.parse()
を使用して、URL文字列を解析し、IPアドレスとポート番号を抽出します。
- URLに関連する情報を扱う必要がある場合は、URLオブジェクトを使用します。
- 構造化されたデータを扱う必要がある場合は、オブジェクトリテラルを使用すると便利です。
- 単純なIPアドレスとポート番号の処理には、文字列または数値として直接扱う方法が適しています。