未使用のローカルポートを見つける最も簡単な方法は何ですか?
現在、私はこれに似たものを使用しています:
port=$RANDOM
quit=0
while [ "$quit" -ne 1 ]; do
netstat -a | grep $port >> /dev/null
if [ $? -gt 0 ]; then
quit=1
else
port=`expr $port + 1`
fi
done
それはひどく回り道をしているので、私が見逃したビルトインのようなもっと単純なパスがあるのだろうかと思います。
アプリケーションでサポートされている場合は、ポート0をアプリケーションに渡してみてください。アプリケーションがこれをカーネルに渡すと、ポートは要求時に動的に割り当てられ、使用されないことが保証されます(すべてのポートがすでに使用されている場合、割り当ては失敗します)。
それ以外の場合は、これを手動で実行できます。あなたの回答のスクリプトには競合状態があり、それを回避する唯一の方法は、それを開こうとすることによってそれが開いているかどうかを原子的にチェックすることです。ポートが使用中の場合、プログラムはポートを開くことに失敗して終了するはずです。
たとえば、GNU netcat。
#!/bin/bash
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
while :; do
for (( port = lower_port ; port <= upper_port ; port++ )); do
nc -l -p "$port" 2>/dev/null && break 2
done
done
私の解決策は、ポート0にバインドすることです。これは、ip_local_port_rangeからポートを割り当てるようカーネルに要求します。次に、ソケットを閉じ、構成でそのポート番号を使用します。
これは、カーネルが絶対に必要になるまでポート番号を再利用しないように見えるためです。その後ポート0にバインドすると、別のポート番号が割り当てられます。 Pythonコード:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 0))
addr = s.getsockname()
print addr[1]
s.close()
これにより、ポートの数だけがわかります。 60123
。
このプログラムを10 000回実行すると(これらを同時に実行する必要があります)、10 000の異なるポート番号が取得されます。したがって、ポートを使用することはかなり安全だと思います。
私は目的を迅速に果たす素敵な1行をまとめました。これは、任意の範囲の任意の数のポートを取得できるようにします(ここでは読みやすくするために4行に分割しています)。
_comm -23 \
<(seq "$FROM" "$TO" | sort) \
<(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) \
| shuf | head -n "$HOWMANY"
_
comm
は、アルファベット順に並べ替えて表示する必要がある2つのファイルの行を比較するユーティリティです。最初のファイルにのみ表示される行、2番目のファイルにのみ表示される行、および共通の行の3つの列を出力します。 _-23
_を指定することにより、後者の列を抑制し、最初の列のみを保持します。これを使用して、一連のテキスト行として表される2つのセットの差を取得できます。 comm
here について学びました。
最初のファイルは、選択可能なポートの範囲です。 seq
は、_$FROM
_から_$TO
_までのソートされた一連の数値を生成します。結果は(comm
s要件に準拠するために、数値ではなく)アルファベット順に並べ替えられ、 プロセス置換 を使用して最初のファイルとしてcomm
にパイプされます。
2番目のファイルは、ss
コマンドを呼び出して取得した、ソートされたポートのリストです(_-t
_は、TCPポート、_-a
_は、すべて-確立され、リスニングしていることを意味します-および_-n
_数値-たとえば、_22
_をssh
に解決しようとしないでください。次に、ローカルアドレスとポートを含むawk
の4番目の列のみを選択します。アドレスを分割するためにcut
を使用します。 _:
_区切り文字を使用して移植し、後者(_-f2
_)のみを保持します。次に、comm
ingによるsort
ingの要件に準拠します。重複する_-u
_は重複しません。
これで、開いているポートのソートされたリストができました。これをshuf
fleして、最初の_"$HOWMANY"
_のものを_head -n
_で取得できます。
プライベート範囲でランダムに開いている3つのポートを取得(49152-65535)
_comm -23 <(seq 49152 65535 | sort) <(ss -Htan | awk '{print $4}' | cut -d':' -f2 | sort -u) | shuf | head -n 3
_
たとえば戻ることができます
_54930
57937
51399
_
ss
で_-t
_を_-u
_に切り替えて、代わりに空きUDPポートを取得します。shuf
を_sort -n
_に置き換えます#!/bin/bash
read LOWERPORT UPPERPORT < /proc/sys/net/ipv4/ip_local_port_range
while :
do
PORT="`shuf -i $LOWERPORT-$UPPERPORT -n 1`"
ss -lpn | grep -q ":$PORT " || break
done
echo $PORT
クリスダウンへのクレジット
どうやら TCP接続はファイル記述子として使用できます Linuxのbash/zshから。次の関数はその手法を使用しており、netcat/telnetを呼び出すよりも高速です。
function EPHEMERAL_PORT() {
LOW_BOUND=49152
RANGE=16384
while true; do
CANDIDATE=$[$LOW_BOUND + ($RANDOM % $RANGE)]
(echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo $CANDIDATE
break
fi
done
}
使用方法:出力を変数にバインドし、スクリプトで使用します。 Ubuntu 16.04でテスト済み
root@ubuntu:~> EPHEMERAL_PORT
59453
root@ubuntu:~> PORT=$(EPHEMERAL_PORT)
Linuxでは、次のようなことができます。
ss -tln |
awk 'NR > 1{gsub(/.*:/,"",$4); print $4}' |
sort -un |
awk -v n=1080 '$0 < n {next}; $0 == n {n++; next}; {exit}; END {print n}'
1080を超える最初の空いているポートを見つけます。ssh -D
はループバックインターフェイスにバインドするため、理論的には、ソケットが別のアドレスにバインドしているポート1080を再利用できます。別の方法は、実際に試してバインドすることです。
Perl -MSocket -le 'socket S, PF_INET, SOCK_STREAM,getprotobyname("tcp");
$port = 1080;
++$port until bind S, sockaddr_in($port,inet_aton("127.1"));
print $port'
以下は、使用中のすべてのポートを解放し、3000以降で最初に使用可能なポートを提供する、クロスプラットフォームで効率的な「oneliner」です。
netstat -aln | awk '
$6 == "LISTEN" {
if ($4 ~ "[.:][0-9]+$") {
split($4, a, /[:.]/);
port = a[length(a)];
p[port] = 1
}
}
END {
for (i = 3000; i < 65000 && p[i]; i++){};
if (i == 65000) {exit 1};
print i
}
'
単純にすべての行を結合して、1行にすることができます。別のポート番号から最初のポートを取得したい場合は、i
ループで割り当てをfor
に変更します。
MacとLinuxの両方で機能するため、[:.]
正規表現が必要です。
これは私が使用するバージョンです:
while
port=$(shuf -n 1 -i 49152-65535)
netstat -atun | grep -q "$port"
do
continue
done
echo "$port"
コマンド shuf -n 1 -i 49152-65535
は、ダイナミックレンジの「ランダム」ポートを提供します。すでに使用されている場合は、その範囲内の別のポートが試行されます。
コマンド netstat -atun
は、すべての(-a)TCP(-t)およびUDP(-u)ポートをリストし、ホスト名を決定するための時間を無駄にしません(-n)。
while port=$(shuf -n1 -i $(cat /proc/sys/net/ipv4/ip_local_port_range | tr '\011' '-'))
netstat -atun | grep -q ":$port\s" ; do
continue
done
echo $port
上記の他の回答からの私の組み合わせ。それを得る:
Shuf -n1を使用して、/ proc/sys/net/ipv4/ip_local_port_rangeの範囲(-i)から1つの乱数を取得します。 shufはダッシュ付きの構文を必要とするため、ダッシュを使用してタブを変更するにはtrを使用します。
次に、netstatを使用して、すべての(-a)tcpおよびudp(-u -t)接続を数値(-n)で表示します。\s)次に、他のポートが必要なので続行します。それ以外の場合(grep -qの戻りコード> 0は、whileループを終了し、$ portが設定されています。
python横になっている場合、私はこれを行います:
port="$(python -c 'import socket; s=socket.socket(); s.bind(("", 0)); print(s.getsockname()[1])')";
echo "Unused Port: $port"
この古い趣味の馬での別の実行:
function random_free_tcp_port {
local ports="${1:-1}" interim="${2:-2048}" spacing=32
local free_ports=( )
local taken_ports=( $( netstat -aln | egrep ^tcp | fgrep LISTEN |
awk '{print $4}' | egrep -o '[0-9]+$' |
sort -n | uniq ) )
interim=$(( interim + (RANDOM % spacing) ))
for taken in "${taken_ports[@]}" 65535
do
while [[ $interim -lt $taken && ${#free_ports[@]} -lt $ports ]]
do
free_ports+=( $interim )
interim=$(( interim + spacing + (RANDOM % spacing) ))
done
interim=$(( interim > taken + spacing
? interim
: taken + spacing + (RANDOM % spacing) ))
done
[[ ${#free_ports[@]} -ge $ports ]] || return 2
printf '%d\n' "${free_ports[@]}"
}
このコードは、netstat
、egrep
、awk
、&alを純粋に移植可能な方法で使用します。最初に取得されたポートのリストを取得するために、呼び出しのみが外部コマンドに対して発行されることに注意してください。 1つ以上の空きポートを要求できます。
:; random_free_tcp_port
2070
:; random_free_tcp_port 2
2073
2114
そして任意のポートから始めます:
:; random_free_tcp_port 2 10240
10245
10293
これは、.bashrcにある関数の一部であり、SSHトンネルを動的に作成し、範囲内の任意のポートを使用しようとします。
lps=( 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 )
lp=null
# find a free listening port
for port in ${lps[@]}; do
lsof -i -n -P |grep LISTEN |grep -q ":${port}"
[ $? -eq 1 ] && { lp=$port; break; }
done
[ "$lp" = "null" ] && { echo "no free local ports available"; return 2; }
return $port
YMMV
私は次のときに役立つかもしれないこの小さなPython2/3スクリプトを書きました:
私の考え...関数はn
連続する空きポートを見つけようとします:
#!/bin/bash
RANDOM=$$
# Based on
# https://unix.stackexchange.com/a/55918/41065
# https://unix.stackexchange.com/a/248319/41065
find_n_ports () {
local n=$1
RANDOM=$$
read lower_port upper_port < /proc/sys/net/ipv4/ip_local_port_range
local tries=10
while [ $((tries--)) -gt 0 ]; do
# Sleep for 100 to 499 ms
sleep "0.$((100+$RANDOM%399))"
local start="`shuf -i $lower_port-$(($upper_port-$n-1)) -n 1`"
local end=$(($start+$n-1))
# create ss filter for $n consecutive ports starting with $start
local filter=""
local ports=$(seq $start $end)
for p in $ports ; do
filter="$filter or sport = $p"
done
# if none of the ports is in use return them
if [ "$(ss -tHn "${filter# or}" | wc -l)" = "0" ] ; then
echo "$ports"
return 0
fi
done
echo "Could not find $n consecutive ports">&2
return 1
}
ports=$(find_n_ports 3)
[ $? -ne 0 ] && exit 1
exit 0