getservbyport#
Αναζήτηση μιας υπηρεσίας δικτύου από την αριθμητική θύρα και το πρωτόκολλό της.
Η getservbyport συμβουλεύεται τη βάση δεδομένων υπηρεσιών του συστήματος (/etc/services σε Linux, συν όποιες πηγές NSS είναι ρυθμισμένες) και επιστρέφει την εγγραφή για την υπηρεσία που ακούει στη PORT υπό το πρωτόκολλο PROTO. Η PORT είναι ένας ακέραιος σε network byte order - η τιμή που θα περνούσατε στην bind ή θα λαμβάνατε από το sockaddr_in, όχι το δεκαδικό που εμφανίζεται στο /etc/services. Το PROTO είναι μια συμβολοσειρά με πεζά όπως "tcp" ή "udp". Η κλήση περιτυλίγει την getservbyport(3) της βιβλιοθήκης C.
Σύνοψη#
getservbyport PORT, PROTO # list context: full record
scalar getservbyport PORT, PROTO # scalar context: service name
Τι επιστρέφεται#
Σε περιβάλλον λίστας, μια λίστα πέντε στοιχείων που περιγράφει την υπηρεσία:
my ($name, $aliases, $port, $proto) = getservbyport($port_n, "tcp");
Δείκτης | Όνομα | Σημασία |
|---|---|---|
0 |
| Κανονικό όνομα υπηρεσίας, π.χ. |
1 |
| Λίστα ψευδωνύμων χωρισμένη με κενά, π.χ. |
2 |
| Αριθμός θύρας σε network byte order |
3 |
| Όνομα πρωτοκόλλου, π.χ. |
Αν η εγγραφή δεν υπάρχει η λίστα είναι κενή, οπότε μια εκχώρηση σε περιβάλλον λίστας αφήνει κάθε στόχο undef. Μια σκέτη κλήση σε περιβάλλον λίστας επιστρέφει μια μοναδική άνευ νοήματος αληθή τιμή σε αστοχία - εκχωρείτε πάντα σε λίστα και ελέγχετε το πρώτο στοιχείο, ή καλείτε σε βαθμωτό περιβάλλον.
Σε βαθμωτό περιβάλλον, παίρνετε το κανονικό όνομα υπηρεσίας (το ίδιο $name όπως παραπάνω), ή undef αν καμία υπηρεσία δεν είναι καταχωρημένη σε αυτή τη θύρα για αυτό το πρωτόκολλο:
my $name = getservbyport($port_n, "tcp")
or warn "port $port not registered for tcp";
Καθολική κατάσταση που επηρεάζει#
Η
$!δεν τίθεται αξιόπιστα σε αστοχία - η συνάρτηση Cgetservbyport(3)δεν έχει τυποποιημένο συμβόλαιο errno για «δεν βρέθηκε». Αντιμετωπίστε μια επιστροφή κενής λίστας ήundefως το μόνο αξιόπιστο σήμα αποτυχίας.Η κατάσταση επανάληψης που κρατά η βάση δεδομένων υπηρεσιών (κοινόχρηστη με τις
getservent,setserventκαιendservent) είναι καθολική σε επίπεδο διεργασίας και δεν είναι ασφαλής για threads.
Παγίδα byte-order#
Η PORT πρέπει να είναι σε network byte order. Η στήλη της θύρας στο /etc/services είναι ανθρώπινο δεκαδικό· η τιμή που χρησιμοποιεί ο πυρήνας και η βιβλιοθήκη C είναι η big-endian 16-bit κωδικοποίηση. Μετατρέψτε με pack / unpack ή με τους βοηθούς Socket:
use Socket;
# Host decimal 80 -> network-order short:
my $port_n = pack("n", 80); # two bytes, big-endian
my @rec = getservbyport($port_n, "tcp");
# Or going the other way, a port extracted from sockaddr_in is
# already network order:
my ($port_n_from_peer, $iaddr) = sockaddr_in(getpeername($sock));
my $name = getservbyport($port_n_from_peer, "tcp");
Το πέρασμα ενός ακεραίου σε host-order όπως 80 λειτουργεί σε υλικό little-endian μόνο κατά λάθος για χαμηλές θύρες των οποίων η κωδικοποίηση τυχαίνει να είναι μη μηδενική στο χαμηλό byte - οι περισσότερες θύρες απλώς θα αστοχήσουν. Αυτός είναι ο πιο κοινός λόγος που μια κλήση getservbyport «επιστρέφει σιωπηρά τίποτα».
Παραδείγματα#
Αναγνώριση της υπηρεσίας στη θύρα 443 μέσω TCP:
use Socket;
my $port_n = pack("n", 443);
my ($name) = getservbyport($port_n, "tcp");
print $name, "\n"; # https
Συνδυασμός με getpeername για ονομασία της θύρας μιας εισερχόμενης σύνδεσης:
use Socket;
my ($peer_port_n, $peer_addr) = sockaddr_in(getpeername($client));
my $service = getservbyport($peer_port_n, "tcp") // "unknown";
print "client connected from service $service\n";
Πλήρης εκτύπωση εγγραφής - χρήσιμη όταν θέλετε το πρωτόκολλο ή τα ψευδώνυμα:
use Socket;
my @rec = getservbyport(pack("n", 53), "udp");
if (@rec) {
my ($name, $aliases, $port_n, $proto) = @rec;
printf "%s (%s) on %d/%s\n",
$name, $aliases, unpack("n", pack("n", $port_n)), $proto;
}
Βαθμωτό περιβάλλον, στυλ ρήτρας φύλακα:
my $svc = getservbyport(pack("n", $port), "tcp")
or die "no TCP service registered on port $port";
Επανάληψη σε κάθε καταχωρημένη υπηρεσία (η υποκείμενη βάση δεδομένων είναι κοινόχρηστη με την getservent):
while (my ($n, $a, $p, $proto) = getservent()) {
next unless $proto eq "tcp";
# …do something with $n / $p…
}
endservent();
Οριακές περιπτώσεις#
Εγγραφή που λείπει: κενή λίστα σε περιβάλλον λίστας,
undefσε βαθμωτό περιβάλλον. Ένα σκέτοif (getservbyport(...))σε περιβάλλον λίστας είναι αληθές ακόμη και για εγγραφή που λείπει λόγω της παλαιάς επιστροφής «μοναδικής άνευ νοήματος αληθούς τιμής» - εκχωρείτε πάντα σε λίστα ή εξαναγκάζετε σε βαθμωτό περιβάλλον.Άγνωστο πρωτόκολλο: μια μη αναγνωρισμένη συμβολοσειρά
PROTO(π.χ."sctp"σε έναν υπολογιστή του οποίου η βάση δεδομένων δεν την περιλαμβάνει) αντιμετωπίζεται από τη βιβλιοθήκη C ως μη-αντιστοιχία. Η κλήση επιστρέφει κενό/undef, όχι σφάλμα.Πεζά/κεφαλαία του
PROTO: ευαίσθητο σε πεζά/κεφαλαία στις περισσότερες υλοποιήσεις libc Linux. Χρησιμοποιήστε πεζά"tcp"/"udp"· το"TCP"θα αστοχήσει.Θύρα σε host-order: το πέρασμα
80αντί γιαpack("n", 80)είναι το κλασικό σφάλμα - δείτε Παγίδα byte-order παραπάνω.Αριθμητική έναντι συμβολοσειράς
PORT: η Perl μετατρέπει αριθμητικά τηνPORTπριν την περάσει στη libc. Μια πακεταρισμένη συμβολοσειρά δύο bytes λειτουργεί επειδή ηpackμε"n"παράγει bytes που μετατρέπονται αριθμητικά ντετερμινιστικά στις υποστηριζόμενες πλατφόρμες· αν υπάρχει αμφιβολία,unpack("n", $packed)πρώτα και περάστε τον ακέραιο ώστε η πρόθεση να μείνει ρητή.Προτεραιότητα με τελεστές λίστας: όπως άλλοι ονομασμένοι μοναδιαίοι / λίστας τελεστές, η
getservbyportσυνδέει χαλαρά. Βάλτε σε παρενθέσεις όταν το αποτέλεσμα τροφοδοτεί άλλον τελεστή:getservbyport $port_n, "tcp" eq "https" # WRONG (getservbyport($port_n, "tcp")) eq "https" # correct
Threads: η υποκείμενη αναζήτηση μοιράζεται κατάσταση με τις
getservent/setservent/endservent. Δύο threads που επαναλαμβάνουν ταυτόχρονα θα διαπλέξουν εγγραφές. Χρησιμοποιήστε thread-local περιτυλίγματα όταν αυτό έχει σημασία.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
getservbyname- αντίστροφη αναζήτηση, όνομα υπηρεσίας σε θύρα· καταφύγετε σε αυτή όταν ξέρετε το όνομα και θέλετε τον αριθμόgetservent- επανάληψη σε κάθε εγγραφή υπηρεσίας· χρησιμοποιήστε όταν χρειάζεστε πλήρη σάρωση παρά μία μεμονωμένη αναζήτησηsetservent- επαναφορά του επαναλήπτη υπηρεσιών, προαιρετική σημαίαSTAYOPENγια να κρατά το αρχείο ανοιχτό μέσωforkendservent- κλείσιμο της βάσης δεδομένων υπηρεσιών μετά από μια επανάληψηgetprotobynumber- η αντίστοιχη αναζήτηση από την πλευρά πρωτοκόλλου· συχνά χρησιμοποιείται αμέσως μετά τηgetservbyportγια να μεταφραστεί το πεδίο$protopack- κατασκευή της τιμής θύρας σε network-order που ηgetservbyportαναμένει ως πρώτο όρισμαSocket- σταθερές και βοηθητικέςsockaddr_inπου παράγουν θύρες σε network-order απευθείας από δομές πυρήνα