「このポートは本当に使われているの?」「アプリが起動しないのはポートが競合しているから?」——こういった場面で活躍するのが netstat コマンドです。
Windows 標準搭載の netstat を使えば、現在開いているポートや確立している通信、ポートを使用しているプロセスを一覧で確認できます。この記事では基本構文からバッチファイルでの自動化まで、実務で使えるパターンを一通り解説します。
netstat コマンドの基本構文とオプション
netstat [オプション] [interval] 主要オプション: -a : すべての接続とリスニングポートを表示 -n : アドレス・ポートを数値で表示(名前解決しない) -o : 各接続に対応するPIDを表示 -b : 各接続を使用している実行ファイル名を表示(管理者権限必要) -p proto : 指定したプロトコルの接続を表示(TCP/UDP/TCPv6/UDPv6) -r : ルーティングテーブルを表示 -s : プロトコル別の統計情報を表示 -e : イーサネット統計を表示 表示間隔(秒数)を指定すると指定秒ごとに繰り返し表示: netstat -ano 5 (5秒ごとに更新)
実務で最もよく使う組み合わせは netstat -ano です。すべての接続・ポートを数値で表示し、対応 PID も確認できます。名前解決しないため表示が速く、スクリプトでのパース処理にも向いています。
ポートの使用状況を確認する
すべての接続・待機ポートを表示
rem 全接続とPIDを数値で表示 netstat -ano rem TCPのみ netstat -ano -p TCP rem UDPのみ netstat -ano -p UDP
出力の各列は「プロトコル・ローカルアドレス・外部アドレス・状態・PID」の順です。
プロトコル ローカル アドレス 外部アドレス 状態 PID TCP 0.0.0.0:80 0.0.0.0:0 LISTENING 1234 TCP 0.0.0.0:443 0.0.0.0:0 LISTENING 1234 TCP 127.0.0.1:3306 0.0.0.0:0 LISTENING 5678 TCP 192.168.1.10:54321 203.0.113.1:443 ESTABLISHED 9012 UDP 0.0.0.0:53 *:* 1234
ローカルアドレスの 0.0.0.0 と 127.0.0.1 の違い
LISTENING 状態のローカルアドレスが何を意味するかを理解しておくと、セキュリティの観点でも役立ちます。
| ローカルアドレス | 意味 | アクセス元 |
|---|---|---|
0.0.0.0:8080 |
全インターフェースで待機 | ローカルマシン・ネットワーク上の他PC 両方からアクセス可 |
127.0.0.1:3306 |
ループバックのみで待機 | ローカルマシンからのみアクセス可(外部からはアクセス不可) |
192.168.1.5:80 |
特定NICのみで待機 | そのIPアドレスのNICが接続するネットワークからのみ |
:::80 |
IPv6の全インターフェースで待機 | IPv4/IPv6 両方から(デュアルスタック) |
0.0.0.0 でリッスンしているサービスは外部からアクセスできる状態です。データベース(MySQL の 3306 など)が 0.0.0.0 でリッスンしていたら、ファイアウォールで遮断されているか確認してください。
特定のポートが使用中か確認する
特定ポートが使用中か確認するには FINDSTR でフィルタリングします。
@echo off
set PORT=8080
netstat -ano | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
if %ERRORLEVEL%==0 (
echo ポート %PORT% は使用中(LISTENING)です。
) else (
echo ポート %PORT% は空き状態です。
)
FINDSTR のパターンは ":%PORT% " のように コロン+ポート番号+スペース で検索してください。こうすることで、ポート 80 の検索で 8080 や 18080 を誤検知しません。ポート番号の後ろのスペースが重要です。
接続状態の種類と意味
| 状態 | 意味 | 確認・対処ポイント |
|---|---|---|
LISTENING |
接続を待ち受け中(サーバーソケット) | サービス・アプリが起動して待機している |
ESTABLISHED |
接続確立中(通信中) | クライアントとサーバーがアクティブに通信している |
TIME_WAIT |
接続クローズ後の待機状態(既定240秒) | 通常は短時間で消える。大量残存は高負荷・ポート不足の可能性 |
CLOSE_WAIT |
相手からの切断を受信し、こちらの切断待ち | 増え続ける場合はアプリがソケットを正しく閉じていないバグの疑い |
SYN_SENT |
接続開始リクエストを送信し、応答待ち | 接続先が応答しない場合に残る。接続先の疎通を確認 |
SYN_RECEIVED |
接続開始リクエストを受信し、確認待ち | SYN フラッド攻撃時に大量発生することがある |
FIN_WAIT_1/2 |
切断処理中 | 通常は瞬間的。残り続ける場合はアプリ側の問題 |
PID からプロセスを特定する
netstat -ano でわかった PID から tasklist でプロセス名を調べます。
@echo off
set PORT=8080
rem 指定ポートをLISTENしているPIDを取得
set PID=
for /f "tokens=5" %%p in (
'netstat -ano ^| findstr ":%PORT% " ^| findstr "LISTENING"'
) do if not defined PID set PID=%%p
if not defined PID (
echo ポート %PORT% を使用しているプロセスは見つかりませんでした。
exit /b 0
)
echo ポート %PORT% を使用しているPID: %PID%
tasklist /fi "PID eq %PID%" /fo table
for /f "tokens=5" で5列目(PID)を取得しています。netstat -ano の出力は「プロトコル・ローカルアドレス・外部アドレス・状態・PID」の順に並んでいます。詳しくは外部コマンドの結果を変数に格納する方法を参照してください。
ポート占有プロセスを確認して終了する
@echo off
setlocal
set PORT=8080
rem PID取得
set PID=
for /f "tokens=5" %%p in (
'netstat -ano ^| findstr ":%PORT% " ^| findstr "LISTENING"'
) do if not defined PID set PID=%%p
if not defined PID (
echo ポート %PORT% は使用されていません。
exit /b 0
)
echo PID %PID% がポート %PORT% を使用しています。
tasklist /fi "PID eq %PID%" /fo list | findstr "イメージ名"
echo このプロセスを終了しますか?
choice /c YN /m "[Y]終了する [N]キャンセル"
if ERRORLEVEL 2 exit /b 0
taskkill /pid %PID% /f
if ERRORLEVEL 1 (
echo [ERROR] プロセスの終了に失敗しました。管理者権限で実行してください。
) else (
echo [OK] PID %PID% を終了しました。
)
バッチファイルでの自動化パターン
パターン1:ポートが開放されるまで待機する
アプリの起動を待ってから次の処理を実行したい場合に使えます。サーバーが起動して特定ポートが LISTEN 状態になるまで待機します。
@echo off
setlocal
set PORT=8080
set TIMEOUT_SEC=60
set ELAPSED=0
echo ポート %PORT% が開放されるまで待機します...
:WAIT_LOOP
netstat -ano | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
if %ERRORLEVEL%==0 (
echo ポート %PORT% が開放されました。(%ELAPSED%秒後)
exit /b 0
)
if %ELAPSED% GEQ %TIMEOUT_SEC% (
echo タイムアウト: %TIMEOUT_SEC%秒待機しましたがポート %PORT% は開放されませんでした。
exit /b 1
)
timeout /t 3 /nobreak >nul
set /a ELAPSED+=3
goto WAIT_LOOP
パターン2:接続数を監視してアラートを出す
@echo off
setlocal enabledelayedexpansion
set PORT=80
set ALERT_COUNT=100
set LOG=C:\logs\netstat_alert.log
if not exist "C:\logs" mkdir "C:\logs"
:MONITOR_LOOP
rem 指定ポートの ESTABLISHED 接続数をカウント
for /f %%c in (
'netstat -ano ^| findstr ":%PORT% " ^| findstr "ESTABLISHED" ^| find /c "ESTABLISHED"'
) do set COUNT=%%c
echo %DATE% %TIME% - ポート %PORT% の接続数: %COUNT% >> "%LOG%"
if %COUNT% GEQ %ALERT_COUNT% (
echo [ALERT] %DATE% %TIME% - ポート %PORT% の接続数が %COUNT% に達しました! >> "%LOG%"
)
timeout /t 30 /nobreak >nul
goto MONITOR_LOOP
パターン3:定期的なポート状態レポートを生成する
@echo off
setlocal
for /f "tokens=1-3 delims=/ " %%a in ("%DATE%") do set DSTR=%%a%%b%%c
set REPORT=C:\logs\port_report_%DSTR%.txt
if not exist "C:\logs" mkdir "C:\logs"
echo ===== ポート状態レポート %DATE% %TIME% ===== > "%REPORT%"
echo. >> "%REPORT%"
echo --- LISTENINGポート一覧 --- >> "%REPORT%"
netstat -ano | findstr "LISTENING" >> "%REPORT%"
echo. >> "%REPORT%"
echo --- ESTABLISHED接続一覧 --- >> "%REPORT%"
netstat -ano | findstr "ESTABLISHED" >> "%REPORT%"
echo. >> "%REPORT%"
for /f %%c in ('netstat -ano ^| findstr "LISTENING" ^| find /c "LISTENING"') do (
echo LISTENING ポート数: %%c >> "%REPORT%"
)
for /f %%c in ('netstat -ano ^| findstr "ESTABLISHED" ^| find /c "ESTABLISHED"') do (
echo ESTABLISHED 接続数: %%c >> "%REPORT%"
)
echo レポートを生成しました: %REPORT%
type "%REPORT%"
パターン4:複数ポートを一括チェックする
@echo off
setlocal enabledelayedexpansion
rem チェック対象ポートリスト
set PORTS=80 443 3306 5432 8080 8443
echo ===== ポート使用状況チェック =====
echo ポート 状態 PID
echo -------- ---------- -----
for %%P in (%PORTS%) do (
set STATUS=空き
set PID=-
for /f "tokens=4,5" %%a in (
'netstat -ano ^| findstr ":%%P " ^| findstr "LISTENING"'
) do (
set STATUS=使用中
set PID=%%b
)
echo %%P !STATUS! !PID!
)
パターン5:TIME_WAIT 状態の大量発生を検知する
高負荷な Web サーバーや API サーバーで TIME_WAIT が大量発生するとポート不足につながることがあります。
@echo off
setlocal
set THRESHOLD=500
set LOG=C:\logs\timewait_monitor.log
if not exist "C:\logs" mkdir "C:\logs"
for /f %%c in (
'netstat -ano ^| findstr "TIME_WAIT" ^| find /c "TIME_WAIT"'
) do set TW_COUNT=%%c
echo %DATE% %TIME% - TIME_WAIT数: %TW_COUNT% >> "%LOG%"
if %TW_COUNT% GEQ %THRESHOLD% (
echo [WARN] TIME_WAIT が %TW_COUNT% に達しています。ポート不足に注意してください。
)
パターン6:特定の外部 IP との接続を確認する
不審な接続先 IP との通信が発生していないか確認したいとき、または特定サーバーへの接続状況を把握したいときに使えます。
@echo off
set TARGET_IP=203.0.113.1
echo %TARGET_IP% との接続一覧:
netstat -ano | findstr "%TARGET_IP%"
rem 接続数をカウント
for /f %%c in ('netstat -ano ^| findstr "%TARGET_IP%" ^| find /c "%TARGET_IP%"') do (
echo 接続数: %%c
)
パターン7:不審ポートの定期スキャンとログ記録
セキュリティ監査として、既知以外のポートが突然 LISTENING になっていないか監視できます。
@echo off
setlocal
set LOG=C:\logs\port_audit.log
if not exist "C:\logs" mkdir "C:\logs"
rem 許可ポートリスト(カンマ区切り)
set ALLOWED=80 443 3389 22 3306 1433
echo ===== ポート監査 %DATE% %TIME% ===== >> "%LOG%"
for /f "tokens=2" %%a in ('netstat -ano ^| findstr "LISTENING"') do (
rem ローカルアドレスからポート番号を取得
for /f "tokens=2 delims=:" %%p in ("%%a") do (
rem 許可リストに含まれているか確認
echo %ALLOWED% | findstr "%%p" >nul 2>&1
if ERRORLEVEL 1 (
echo [UNKNOWN PORT] %%p - %%a >> "%LOG%"
)
)
)
echo 監査完了。ログ: %LOG%
実行ファイル名も表示する(-b オプション)
-b オプションを使うと、各接続に対応する実行ファイル名(.exe)を表示できます。管理者権限が必要です。
rem 管理者権限が必要 netstat -anob rem 特定ポートに絞り込む netstat -anob | findstr ":8080"
-b は実行が遅くなります。通常は -ano で PID を取得してから tasklist /fi "PID eq XXX" で確認する方が高速です。
ルーティングテーブルを確認する(-r)
rem ルーティングテーブルを表示(route print と同等) netstat -r rem デフォルトゲートウェイを確認 netstat -r | findstr "0.0.0.0"
プロトコル統計を確認する(-s)
TCP/UDP/ICMP などのプロトコルごとの統計情報を表示します。パケットロスや再送数の確認に使えます。
rem 全プロトコルの統計 netstat -s rem TCP統計のみ netstat -s -p TCP
TCP 統計の「Segments Retransmitted」(再送セグメント数)が多い場合はネットワーク品質の問題が考えられます。
netstat と PowerShell の比較
Windows PowerShell には Get-NetTCPConnection コマンドがあり、netstat より柔軟なフィルタリングができます。
| 操作 | netstat(bat) | PowerShell |
|---|---|---|
| 全接続表示 | netstat -ano |
Get-NetTCPConnection |
| 特定ポートで絞り込み | findstr ":8080 " |
| Where-Object LocalPort -eq 8080 |
| PIDからプロセス名 | tasklist /fi "PID eq XXX" |
Get-Process -Id (PID) |
| 速度 | 速い | やや遅い(起動コスト) |
| 日本語環境での安定性 | 列幅が変わる場合がある | オブジェクト処理なので安定 |
@echo off set PORT=8080 powershell -command "Get-NetTCPConnection -LocalPort %PORT% -State Listen -ErrorAction SilentlyContinue | Select-Object LocalPort,State,OwningProcess | Format-Table -AutoSize"
TIME_WAIT が大量発生する場合の対処
高負荷サーバーで TIME_WAIT が大量発生してポート不足になる場合、レジストリで待機時間を短縮できます。ただし本番環境での変更は慎重に行ってください。
rem TcpTimedWaitDelay を 30秒に短縮(デフォルト240秒) rem ★本番環境での変更は事前にバックアップを取り、影響を十分確認すること★ reg add "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v TcpTimedWaitDelay /t REG_DWORD /d 30 /f rem MaxUserPort を増やしてポール枯渇を防ぐ(デフォルト5000→65534) reg add "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" /v MaxUserPort /t REG_DWORD /d 65534 /f rem 変更後は再起動が必要 echo 変更を適用するには再起動が必要です。
レジストリを誤って変更するとシステムに深刻な影響が出ることがあります。変更前に必ずバックアップを取り、テスト環境で検証してから本番に適用してください。
よくあるトラブルと対処法
| 症状 | 原因 | 対処法 |
|---|---|---|
| アプリが起動しない(ポート競合) | 既に別プロセスが同じポートを使用している | netstat -ano | findstr ":ポート番号 " で PID を確認し、不要なら taskkill で終了 |
| netstat の出力が遅い | 名前解決に時間がかかっている | 必ず -n を付けて数値表示にする |
| -b オプションが使えない | 管理者権限がない | 管理者として実行する |
| TIME_WAIT が大量に残る | 短時間に大量の接続を処理している | TIME_WAIT は一定時間で自動解消。永続する場合はレジストリの TcpTimedWaitDelay を調整(要注意) |
| CLOSE_WAIT が増え続ける | アプリがソケットを閉じていない(バグ) | 対象プロセスの再起動。根本的にはアプリ側でソケットを適切に close() する修正が必要 |
| 0.0.0.0:3306 が外部公開されている | MySQL等DBが全NICでリッスンしている | bind-address=127.0.0.1 に変更してローカルのみにするか、ファイアウォールで外部からのアクセスを遮断 |
| findstr でポート番号を絞り込むと誤検知する | ポート 80 の検索で 8080 がヒットする等 | ":80 " のようにコロンと後ろのスペースも含めて検索する |
| バッチで for /f のパースが失敗する | 日本語環境で列数が変わる場合がある | 出力を一時ファイルに書き出して確認するか、PowerShell の Get-NetTCPConnection を使う |
まとめ
| やりたいこと | コマンド |
|---|---|
| 全接続とPIDを表示 | netstat -ano |
| 特定ポートが使用中か確認 | netstat -ano | findstr ":8080 " | findstr "LISTENING" |
| TCPのみ表示 | netstat -ano -p TCP |
| LISTENING ポートのみ表示 | netstat -ano | findstr "LISTENING" |
| PIDからプロセス名を調べる | tasklist /fi "PID eq 1234" |
| 実行ファイル名も表示(管理者) | netstat -anob |
| ルーティングテーブル確認 | netstat -r |
| プロトコル統計 | netstat -s -p TCP |
| 接続数をカウント | netstat -ano | findstr "ESTABLISHED" | find /c "ESTABLISHED" |
バッチファイルで netstat を活用する場合は for /f と findstr の組み合わせが基本です。PID の取得には tokens=5 が定番パターンです。ネットワーク接続確認やIPアドレス取得などの関連記事もあわせて参照してください。
よくある質問
":8080 "(コロン + ポート番号 + スペース)のように絞り込むと誤検知を防げます。それでも不安なら findstr /r ":8080[^0-9]" という正規表現パターンも使えます。

