Υποδοχές (sockets)

bind#

Σύνδεση τοπικής διεύθυνσης σε μια υποδοχή.

Η bind είναι το περιτύλιγμα της Perl για την κλήση συστήματος POSIX bind(2). Συσχετίζει το ήδη ανοιγμένο filehandle SOCKET με την τοπική διεύθυνση NAME, ώστε οι επόμενες κλήσεις listen / accept (για διακομιστή) ή connect / send (για πελάτη με σταθερή τοπική διεύθυνση) να χρησιμοποιούν αυτή τη διεύθυνση ως πηγή τους. Το NAME είναι μια πακεταρισμένη δομή διεύθυνσης στη μορφή που αναμένει η οικογένεια διευθύνσεων της υποδοχής - η εργασία του πακεταρίσματος είναι δική σας, τυπικά μέσω βοηθητικών συναρτήσεων του Socket όπως `sockaddr_in` ή `sockaddr_un`.

Σύνοψη#

bind SOCKET, NAME

Τι επιστρέφεται#

Αληθής τιμή σε επιτυχία, ψευδής σε αποτυχία (με την $! να τίθεται στο υποκείμενο errno: EADDRINUSE, EACCES, EADDRNOTAVAIL, κ.λπ.). Ελέγχετε πάντα την τιμή επιστροφής - σε αντίθεση με την print, μια αποτυχημένη bind είναι σφάλμα κατά τη φάση ρύθμισης που πρέπει να ματαιώσει το πρόγραμμα:

bind $sock, $addr
    or die "bind failed: $!";

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

Καμία άμεσα. Η bind θέτει την $! σε αποτυχία· αυτή είναι η μόνη καθολική του διερμηνέα που εμπλέκεται. Η ίδια η υποδοχή πρέπει να είναι ήδη ανοιχτή - τυπικά παράγεται από την socket ή την socketpair - και η bind μεταβάλλει την κατάστασή της στην πλευρά του πυρήνα, όχι κάποια μεταβλητή σε επίπεδο Perl.

Παραδείγματα#

Δέσμευση μιας υποδοχής διακομιστή TCP στη θύρα 9000 σε όλες τις τοπικές διεπαφές και έναρξη ακρόασης. Το INADDR_ANY επιλέγει «οποιαδήποτε τοπική διεύθυνση»· η πακεταρισμένη μορφή προέρχεται από το `sockaddr_in`:

use Socket;

socket(my $srv, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
    or die "socket: $!";
bind($srv, sockaddr_in(9000, INADDR_ANY))
    or die "bind: $!";
listen($srv, SOMAXCONN)
    or die "listen: $!";

Δέσμευση μιας υποδοχής πελάτη σε συγκεκριμένη τοπική διεύθυνση πριν τη σύνδεση - χρησιμοποιείται όταν ο απομακρυσμένος ομότιμος φιλτράρει με βάση τη διεύθυνση IP πηγής, ή όταν ένας υπολογιστής διαθέτει πολλές διεπαφές και χρειάζεστε την εξερχόμενη κίνηση σε συγκεκριμένη:

use Socket;

socket(my $cli, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
    or die "socket: $!";
bind($cli, sockaddr_in(0, inet_aton("192.0.2.17")))
    or die "bind: $!";          # port 0 = kernel picks one
connect($cli, sockaddr_in(443, inet_aton("93.184.216.34")))
    or die "connect: $!";

Δέσμευση ενός ακροατή τομέα UNIX σε μια διαδρομή του συστήματος αρχείων. Η διαδρομή δεν πρέπει να υπάρχει ήδη - η bind δημιουργεί τον κόμβο υποδοχής και τον αφήνει πίσω όταν η διεργασία τερματίσει, οπότε καθαρίστε τον μόνοι σας:

use Socket;

my $path = "/tmp/myapp.sock";
unlink $path;                   # clear stale socket from prior run
socket(my $srv, PF_UNIX, SOCK_STREAM, 0)
    or die "socket: $!";
bind($srv, sockaddr_un($path))
    or die "bind $path: $!";
listen($srv, 5) or die "listen: $!";

Δέσμευση μιας υποδοχής UDP σε σταθερή τοπική θύρα, ώστε οι απαντήσεις από τον ομότιμο να επιστρέφουν σε προβλέψιμη διεύθυνση:

use Socket;

socket(my $udp, PF_INET, SOCK_DGRAM, getprotobyname("udp"))
    or die "socket: $!";
bind($udp, sockaddr_in(5300, INADDR_ANY))
    or die "bind: $!";

Η εκ νέου δέσμευση μιας προηγουμένως απελευθερωμένης θύρας σε σύντομο χρονικό διάστημα απαιτεί το SO_REUSEADDR· αλλιώς η bind αποτυγχάνει με EADDRINUSE κατά τη διάρκεια του παραθύρου TIME_WAIT:

use Socket;

setsockopt($srv, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
    or die "setsockopt: $!";
bind($srv, sockaddr_in(9000, INADDR_ANY))
    or die "bind: $!";

Οριακές περιπτώσεις#

  • Το SOCKET πρέπει να είναι ήδη ανοιχτό. Η bind δεν δημιουργεί την υποδοχή - καλέστε πρώτα την socket. Ένα κλειστό ή ποτέ-ανοιγμένο filehandle αποτυγχάνει με EBADF.

  • Το NAME είναι μια πακεταρισμένη συμβολοσειρά bytes, όχι αναγνώσιμη από άνθρωπο διεύθυνση. Περάστε την έξοδο των `sockaddr_in`, `sockaddr_in6` ή `sockaddr_un` από το Socket. Το πέρασμα μιας απλής συμβολοσειράς όπως "127.0.0.1:9000" παράγει EINVAL ή χειρότερα - ο πυρήνας διαβάζει τα bytes ως struct sockaddr.

  • Η θύρα 0 σημαίνει «αφήστε τον πυρήνα να επιλέξει». Μετά από μια επιτυχημένη bind με θύρα 0, ανακτήστε την πραγματική θύρα με την getsockname και το `sockaddr_in` σε λειτουργία αποπακεταρίσματος.

  • Οι θύρες κάτω από 1024 απαιτούν αυξημένα προνόμια σε Unix - η bind αποτυγχάνει με EACCES για μια διεργασία χωρίς προνόμια.

  • Το EADDRINUSE είναι η πιο κοινή αποτυχία. Πυροδοτείται όταν μια άλλη διεργασία κατέχει τη διεύθυνση, όταν μια προγενέστερη υποδοχή στην ίδια διεύθυνση βρίσκεται ακόμα σε TIME_WAIT, ή όταν καλείτε την bind δύο φορές στην ίδια υποδοχή. Το SO_REUSEADDR (βλέπε setsockopt) αντιμετωπίζει την περίπτωση TIME_WAIT· οι υπόλοιπες είναι γνήσιες συγκρούσεις.

  • Οι υποδοχές τομέα UNIX αφήνουν πίσω εγγραφή στο σύστημα αρχείων που επιβιώνει της διεργασίας. Αφαιρέστε την πριν από μια νέα bind (unlink $path) και κατά τον καθαρό τερματισμό.

  • Η δέσμευση μετά από connect είναι σφάλμα. Όταν μια υποδοχή έχει συνδεθεί, η τοπική της διεύθυνση είναι καθορισμένη. Καλέστε πρώτα την bind αν χρειάζεστε συγκεκριμένη διεύθυνση πηγής.

  • Οι υποδοχές IPv6 χρησιμοποιούν `sockaddr_in6` και PF_INET6· η ανάμειξη οικογενειών μεταξύ της υποδοχής και της πακεταρισμένης διεύθυνσης αποτυγχάνει με EAFNOSUPPORT.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42.

Δείτε επίσης#

  • socket - δημιουργία του filehandle υποδοχής στο οποίο συνδέεται η bind· πρέπει να καλείται πρώτη

  • connect - το αντίστοιχο στην πλευρά του πελάτη· θέτει την απομακρυσμένη διεύθυνση αντί της τοπικής

  • listen - επισήμανση μιας δεσμευμένης υποδοχής ως πρόθυμης να δεχτεί εισερχόμενες συνδέσεις

  • accept - άντληση της επόμενης εκκρεμούς σύνδεσης από μια δεσμευμένη υποδοχή που ακούει

  • getsockname - ανάκτηση της πραγματικής διεύθυνσης που επέλεξε η bind, ειδικά μετά από δέσμευση στη θύρα 0

  • setsockopt - ορισμός του SO_REUSEADDR και άλλων πριν την bind για έλεγχο της επαναχρησιμοποίησης διεύθυνσης

  • Socket - πακετάρει και αποπακετάρει το όρισμα NAME· πηγή των `sockaddr_in`, `sockaddr_un`, INADDR_ANY, PF_INET και σχετικών σταθερών