Test à partir du script shell si le port TCP distant est ouvert
je cherche une méthode simple et rapide pour tester correctement si un port TCP donné est ouvert sur un serveur distant, à partir d'un script Shell.
j'ai réussi à le faire avec la commande telnet, et ça marche très bien quand le port est ouvert, mais ça ne semble pas être le temps mort quand ce n'est pas le cas et ça reste là...
voici un échantillon:
l_TELNET=`echo "quit" | telnet $SERVER $PORT | grep "Escape character is"`
if [ "$?" -ne 0 ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
soit j'ai besoin d'une meilleure façon, ou d'un moyen de forcer telnet à la timeout si elle ne se connecte pas en moins de 8 secondes par exemple, et renvoie quelque chose que je peux attraper dans Shell (code de retour, ou chaîne dans stdout).
je connais la méthode Perl, qui utilise le module IO::Socket::INET et écrit un script qui teste un port, mais qui préfère éviter D'utiliser Perl si possible.
Note: C'est ce que mon serveur exécute (à partir duquel je dois l'exécuter)
SunOS 5.10 Generic_139556-08 i86pc i386 i86pc
16 réponses
comme L'a souligné B. Rhodes, nc
fera le travail. Une façon plus compacte de l'utiliser:
nc -z <host> <port>
de cette façon nc
vérifiera seulement si le port est ouvert, sortant avec 0 sur le succès, 1 sur l'échec.
pour une vérification interactive rapide (avec un temps d'arrêt de 5 secondes):
nc -z -v -w5 <host> <port>
il est assez facile de faire avec le -z
et -w TIMEOUT
options à nc
, mais pas tous les systèmes ont nc
installé. Si vous avez une version assez récente de bash, cela fonctionnera:
# Connection successful:
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/80'
$ echo $?
0
# Connection failure prior to the timeout
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/sfsfdfdff.com/80'
bash: sfsfdfdff.com: Name or service not known
bash: /dev/tcp/sfsfdfdff.com/80: Invalid argument
$ echo $?
1
# Connection not established by the timeout
$ timeout 1 bash -c 'cat < /dev/null > /dev/tcp/google.com/81'
$ echo $?
124
ce qui se passe ici est que timeout
lancera la sous-commande et la tuera si elle ne sort pas dans le délai spécifié (1 seconde dans l'exemple ci-dessus). Dans ce cas bash
est la sous-commande et utilise son /dev/tcp manipulation pour essayer de l'ouvrir une connexion au serveur et le port spécifiés. Si bash
peut ouvrir la connexion dans le délai imparti, cat
va juste la fermer immédiatement (puisqu'elle lit de /dev/null
) et sortir avec un code d'état de 0
qui se propagera par bash
et puis timeout
. Si bash
obtient une défaillance de connexion avant le délai spécifié, alors bash
sortira avec un code de sortie de 1 qui timeout
reviendra aussi. Et si bash n'est pas capable d'établir une connexion et que le délai spécifié expire, alors timeout
tuera bash
et sortira avec un statut de 124.
table des matières:
- utilisant bash et
timeout
- commande
- exemples
- utilisant
nc
- commande
- RHEL 6 (nc-1.84)
- Installation
- exemples
- RHEL 7 (nmap-ncat-6.40)
- Installation
- exemples
- Remarques
utilisant bash et timeout
:
notez que timeout
doit être présent avec RHEL 6+, ou se trouve alternativement dans GNU coreutils 8.22. Sur MacOS, installez-le en utilisant brew install coreutils
et utilisez-le comme gtimeout
.
$ timeout $TIMEOUT_SECONDS bash -c "</dev/tcp/${HOST}/${PORT}"; echo $?
si vous paramétrez l'hôte et le port, assurez-vous de Les spécifier comme ${HOST}
et ${PORT}
comme ci-dessus. Ne les spécifiez pas simplement comme $HOST
et $PORT
, c.-à-d. sans les bretelles; cela ne fonctionnera pas dans ce cas.
exemple:
Succès:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/80"; echo $?
0
echec:
$ timeout 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
124
si vous devez conserver le statut de sortie de bash
,
$ timeout --preserve-status 2 bash -c "</dev/tcp/canyouseeme.org/81"; echo $?
143
utilisant nc
:
notez qu'une version en arrière incompatible de nc
est installée sur RHEL 7.
commande:
notez que la commande ci-dessous est unique en ce qu'elle est identique pour les RHEL 6 et 7. C'est juste l'installation et la sortie qui sont différentes.
$ nc -w $TIMEOUT_SECONDS -v $HOST $PORT </dev/null; echo $?
RHEL 6 (nc-1.84):
Installation:
$ sudo yum install nc
exemples:
Succès:$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Connection to canyouseeme.org 80 port [tcp/http] succeeded!
0
Échec:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
nc: connect to canyouseeme.org port 81 (tcp) timed out: Operation now in progress
1
si le nom d'hôte correspond à plusieurs IPs, la commande ci-dessus passera par plusieurs ou tous. Par exemple:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
nc: connect to microsoft.com port 81 (tcp) timed out: Operation now in progress
1
RHEL 7 (nmap-ncat-6.40):
Installation:
$ sudo yum install nmap-ncat
exemples:
Succès:$ nc -w 2 -v canyouseeme.org 80 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connected to 52.202.215.126:80.
Ncat: 0 bytes sent, 0 bytes received in 0.22 seconds.
0
Échec:
$ nc -w 2 -v canyouseeme.org 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection timed out.
1
Si le nom d'hôte est associé à plusieurs IPs, la commande ci-dessus passera par plusieurs ou la totalité d'entre eux. Par exemple:
$ nc -w 2 -v microsoft.com 81 </dev/null; echo $?
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Connection to 104.43.195.251 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.100.122.175 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 23.96.52.53 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection to 191.239.213.197 failed: Connection timed out.
Ncat: Trying next address...
Ncat: Connection timed out.
1
remarques:
l'argument -v
( --verbose
) et la commande echo $?
sont bien sûr à titre d'illustration seulement.
Avec netcat
, vous pouvez vérifier si un port est ouvert comme ceci:
nc my.example.com 80 < /dev/null
la valeur de retour de nc
sera un succès si le port TCP a été ouvert, et un échec (typiquement le code de retour 1) s'il ne pouvait pas faire la connexion TCP.
en Bash en utilisant les fichiers de pseudo-périphérique pour les connexions TCP/UDP est simple. Voici le script:
#!/usr/bin/env bash
SERVER=example.com
PORT=80
</dev/tcp/$SERVER/$PORT
if [ "$?" -ne 0 ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
Test:
$ ./test.sh
Connection to example.com on port 80 succeeded
Voici une ligne (syntaxe de Bash):
</dev/tcp/localhost/11211 && echo Port open. || echo Port closed.
notez que certains serveurs peuvent être protégés par un pare-feu contre les attaques SYN flood, de sorte que vous pouvez éprouver un délai de connexion TCP (~75secs). De contourner la question de l'heure d'arrêt, essayer:
timeout 1 bash -c "</dev/tcp/stackoverflow.com/81" && echo Port open. || echo Port closed.
Voir: Comment réduire le TCP connect() de l'appel système timeout?
bien qu'il s'agisse d'une vieille question, je viens d'en traiter une variante, mais aucune des solutions ici n'était applicable, donc j'en ai trouvé une autre, et je l'ajoute pour la postérité. Oui, je sais que L'OP a dit qu'ils étaient au courant de cette option et que cela ne leur convenait pas, mais pour quiconque suivrait par la suite, cela pourrait s'avérer utile.
dans mon cas, je veux tester la disponibilité d'un service local apt-cacher-ng
à partir d'un service docker
. Que signifie absolument rien ne peut être installé avant le test. Non. nc
, nmap
, expect
, telnet
ou python
. perl
cependant est présent, avec les bibliothèques de base, donc j'ai utilisé ceci:
perl -MIO::Socket::INET -e 'exit(! defined( IO::Socket::INET->new("172.17.42.1:3142")))'
si vous utilisez ksh ou bash ils supportent tous les deux la redirection IO vers/à partir d'une socket en utilisant la construction /dev/tcp/IP/PORT . Dans cet exemple Korn shell je redirige no-op's ( : ) std-in à partir d'une socket:
W$ python -m SimpleHTTPServer &
[1] 16833
Serving HTTP on 0.0.0.0 port 8000 ...
W$ : </dev/tcp/127.0.0.1/8000
le shell affiche une erreur si la prise n'est pas ouverte:
W$ : </dev/tcp/127.0.0.1/8001
ksh: /dev/tcp/127.0.0.1/8001: cannot open [Connection refused]
vous pouvez donc utiliser il s'agit de l'essai dans une si condition:
SERVER=127.0.0.1 PORT=8000
if (: < /dev/tcp/$SERVER/$PORT) 2>/dev/null
then
print succeeded
else
print failed
fi
le no-op est dans un sous-sol donc je peux jeter std-err si la redirection std-in échoue.
j'utilise souvent / dev /tcp pour vérifier la disponibilité D'une ressource sur HTTP:
W$ print arghhh > grr.html
W$ python -m SimpleHTTPServer &
[1] 16863
Serving HTTP on 0.0.0.0 port 8000 ...
W$ (print -u9 'GET /grr.html HTTP/1.0\n';cat <&9) 9<>/dev/tcp/127.0.0.1/8000
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/2.6.1
Date: Thu, 14 Feb 2013 12:56:29 GMT
Content-type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Feb 2013 12:55:44 GMT
arghhh
W$
Ce one-liner s'ouvre descripteur de fichier 9 pour la lecture et l'écriture à l' socket, imprime le HTTP GET sur la socket et utilise cat
pour lire à partir de la socket.
j'avais besoin d'une solution plus flexible pour travailler sur plusieurs dépôts git et j'ai donc écrit le Code sh suivant basé sur 1 et 2 . Vous pouvez utiliser votre adresse de serveur au lieu de gitlab.com et votre port en remplacement de 22.
SERVER=gitlab.com
PORT=22
nc -z -v -w5 $SERVER $PORT
result1=$?
#Do whatever you want
if [ "$result1" != 0 ]; then
echo 'port 22 is closed'
else
echo 'port 22 is open'
fi
dans certains cas où des outils comme curl, telnet, nc OMAP ne sont pas disponibles, vous avez encore une chance avec wget
if [[ $(wget -q -t 1 --spider --dns-timeout 3 --connect-timeout 10 host:port; echo $?) -eq 0 ]]; then echo "OK"; else echo "FAIL"; fi
si vous voulez utiliser nc
mais n'avez pas de version qui supporte -z
, essayez d'utiliser --send-only
:
nc --send-only <IP> <PORT> </dev/null
et avec timeout:
nc -w 1 --send-only <IP> <PORT> </dev/null
et sans recherche DNS si C'est un IP:
nc -n -w 1 --send-only <IP> <PORT> </dev/null
renvoie les codes comme le -z
basé sur si elle peut se connecter ou non.
je suppose qu'il est trop tard pour une réponse, et peut-être pas une bonne idée, mais ici vous allez...
pourquoi ne pas le mettre dans une boucle de temps avec une minuterie. Je suis plus un gars Perl que Solaris, mais selon la coquille que vous utilisez, vous devriez être en mesure de faire quelque chose comme:
TIME = 'date +%s' + 15
while TIME != `date +%s'
do whatever
et puis ajoutez juste un drapeau dans la boucle while, de sorte que si elle s'étale avant de terminer, vous pouvez citer le timeout comme raison de l'échec.
je soupçonne que le telnet a un interrupteur de temporisation aussi, mais juste au-dessus de ma tête, je pense que le dessus fonctionnera.
j'ai eu besoin de script court qui a été exécuté en cron et n'a pas produit. Je résous mon problème en utilisant nmap
open=`nmap -p $PORT $SERVER | grep "$PORT" | grep open`
if [ -z "$open" ]; then
echo "Connection to $SERVER on port $PORT failed"
exit 1
else
echo "Connection to $SERVER on port $PORT succeeded"
exit 0
fi
pour l'exécuter, vous devez installer nmap car il ne s'agit pas d'un paquet installé par défaut.
cela utilise telnet dans les coulisses, et semble bien fonctionner sur mac/linux. Il n'utilise pas netcat en raison des différences entre les versions sur linux/mac, et cela fonctionne avec une installation mac par défaut.
exemple:
$ is_port_open.sh 80 google.com
OPEN
$ is_port_open.sh 8080 google.com
CLOSED
is_port_open.sh
PORT=
HOST=
TIMEOUT_IN_SEC=${3:-1}
VALUE_IF_OPEN=${4:-"OPEN"}
VALUE_IF_CLOSED=${5:-"CLOSED"}
function eztern()
{
if [ "" == "" ]
then
echo
else
echo
fi
}
# cross platform timeout util to support mac mostly
# https://gist.github.com/jaytaylor/6527607
function eztimeout() { perl -e 'alarm shift; exec @ARGV' "$@"; }
function testPort()
{
OPTS=""
# find out if port is open using telnet
# by saving telnet output to temporary file
# and looking for "Escape character" response
# from telnet
FILENAME="/tmp/__port_check_$(uuidgen)"
RESULT=$(eztimeout $TIMEOUT_IN_SEC telnet $HOST $PORT &> $FILENAME; cat $FILENAME | tail -n1)
rm -f $FILENAME;
SUCCESS=$(eztern "$RESULT" "Escape character is '^]'." "$VALUE_IF_OPEN" "$VALUE_IF_CLOSED")
echo "$SUCCESS"
}
testPort
vérifier les ports à l'aide de bash
exemple
$ ./test_port_bash.sh 192.168.7.7 22
le port 22 est ouvert
Code
HOST=
PORT=
exec 3> /dev/tcp/${HOST}/${PORT}
if [ $? -eq 0 ];then echo "the port is open";else echo "the port is closed";fi
en S'appuyant sur la réponse la plus votée, voici une fonction pour attendre que deux ports soient ouverts, avec un temps mort aussi. Notez les deux ports qui doivent être ouverts, 8890 et 1111, ainsi que le max_attempts (1 par seconde).
function wait_for_server_to_boot()
{
echo "Waiting for server to boot up..."
attempts=0
max_attempts=30
while ( nc 127.0.0.1 8890 < /dev/null || nc 127.0.0.1 1111 < /dev/null ) && [[ $attempts < $max_attempts ]] ; do
attempts=$((attempts+1))
sleep 1;
echo "waiting... (${attempts}/${max_attempts})"
done
}
nmap-ncat de test pour le port local qui n'est pas déjà en cours d'utilisation
availabletobindon() {
port=""
nc -w 2 -i 1 localhost "$port" 2>&1 | grep -v -q 'Idle timeout expired'
return "$?"
}