Πληροφορίες δικτύου

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

$name

Κανονικό όνομα υπηρεσίας, π.χ. "http"

1

$aliases

Λίστα ψευδωνύμων χωρισμένη με κενά, π.χ. "www www-http"

2

$port

Αριθμός θύρας σε network byte order

3

$proto

Όνομα πρωτοκόλλου, π.χ. "tcp"

Αν η εγγραφή δεν υπάρχει η λίστα είναι κενή, οπότε μια εκχώρηση σε περιβάλλον λίστας αφήνει κάθε στόχο undef. Μια σκέτη κλήση σε περιβάλλον λίστας επιστρέφει μια μοναδική άνευ νοήματος αληθή τιμή σε αστοχία - εκχωρείτε πάντα σε λίστα και ελέγχετε το πρώτο στοιχείο, ή καλείτε σε βαθμωτό περιβάλλον.

Σε βαθμωτό περιβάλλον, παίρνετε το κανονικό όνομα υπηρεσίας (το ίδιο $name όπως παραπάνω), ή undef αν καμία υπηρεσία δεν είναι καταχωρημένη σε αυτή τη θύρα για αυτό το πρωτόκολλο:

my $name = getservbyport($port_n, "tcp")
    or warn "port $port not registered for tcp";

Καθολική κατάσταση που επηρεάζει#

  • Η $! δεν τίθεται αξιόπιστα σε αστοχία - η συνάρτηση C getservbyport(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 για να κρατά το αρχείο ανοιχτό μέσω fork

  • endservent - κλείσιμο της βάσης δεδομένων υπηρεσιών μετά από μια επανάληψη

  • getprotobynumber - η αντίστοιχη αναζήτηση από την πλευρά πρωτοκόλλου· συχνά χρησιμοποιείται αμέσως μετά τη getservbyport για να μεταφραστεί το πεδίο $proto

  • pack - κατασκευή της τιμής θύρας σε network-order που η getservbyport αναμένει ως πρώτο όρισμα

  • Socket - σταθερές και βοηθητικές sockaddr_in που παράγουν θύρες σε network-order απευθείας από δομές πυρήνα