Υποδοχές (sockets)

setsockopt#

Θέτει σε ανοιχτή υποδοχή μια επιλογή σε επίπεδο πυρήνα.

Η setsockopt είναι το περιτύλιγμα Perl γύρω από την κλήση συστήματος POSIX setsockopt(2). Γράφει την επιλογή που κατονομάζει το OPTNAME στο LEVEL πρωτοκόλλου, στο ήδη ανοιγμένο filehandle SOCKET, χρησιμοποιώντας την τιμή πακεταρισμένη στο OPTVAL. Είναι το κουμπί για όλα όσα ο πυρήνας σας αφήνει να ρυθμίσετε σε μια υποδοχή - επαναχρήση διεύθυνσης, keepalives, χρονικά όρια, αλγόριθμος του Nagle, συμμετοχή σε multicast, μεγέθη ενταμιευτών αποστολής και λήψης, συμπεριφορά του SO_LINGER στο close, και ούτω καθεξής. Τα συμβολικά ονόματα για το LEVEL και το OPTNAME προέρχονται από το άρθρωμα Socket.

Σύνοψη#

setsockopt SOCKET, LEVEL, OPTNAME, OPTVAL

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

Αληθής τιμή σε επιτυχία, undef σε αποτυχία (με την $! τεθειμένη στο υποκείμενο errno: EBADF, ENOPROTOOPT, EINVAL, ENOTSOCK, κ.λπ.). Πάντα ελέγχετε την τιμή επιστροφής - μια σιωπηρά αγνοημένη επιλογή σημαίνει ότι το πρόγραμμα τρέχει με προεπιλογές που διαφέρουν από αυτό που διαβάζει ο κώδικας:

setsockopt($sock, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
    or die "setsockopt SO_REUSEADDR: $!";

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

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

OPTVAL - πακεταρισμένα bytes ή σκέτος ακέραιος#

Οι περισσότερες επιλογές υποδοχών δέχονται σημαία C int. Η setsockopt δέχεται και τις δύο μορφές για ευκολία:

  • Μια πακεταρισμένη συμβολοσειρά bytes της οποίας η διάταξη ταιριάζει με τον τύπο C της επιλογής, τυπικά δομημένη με pack: pack("l", 1) για λογική τιμή, pack("ll", $on_secs, $on_usecs) για struct timeval, pack("ii", $on, $linger) για struct linger.

  • Έναν απλό ακέραιο, που είναι συντομογραφία για το pack("i", OPTVAL). Βολικό για SO_REUSEADDR, TCP_NODELAY, και άλλες λογικές σημαίες:

    setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, 1);
    

Επιλογές των οποίων η τιμή είναι struct (SO_LINGER, SO_RCVTIMEO, IP_ADD_MEMBERSHIP) πρέπει να περαστούν ως ρητά πακεταρισμένη συμβολοσειρά μέσω pack. Σκέτος ακέραιος εκεί παράγει EINVAL ή, χειρότερα, γράφει σιωπηρά μνήμη λάθος μεγέθους που ο πυρήνας παρερμηνεύει.

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

Απενεργοποιήστε τον αλγόριθμο του Nagle σε υποδοχή TCP ώστε μικρές εγγραφές να φεύγουν αμέσως - χρήσιμο για πρωτόκολλα ευαίσθητα σε καθυστέρηση (διαδραστικά κελύφη, κίνηση παιχνιδιών, RPC):

use Socket qw(IPPROTO_TCP TCP_NODELAY);

setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, 1)
    or die "TCP_NODELAY: $!";

Επιτρέψτε σε διακομιστή να επανασυνδέσει θύρα που εξακολουθεί να είναι σε TIME_WAIT από προηγούμενη διεργασία - η μοναδικά πιο κοινή κλήση setsockopt στην πράξη, και πρέπει να γίνει πριν την bind:

use Socket qw(SOL_SOCKET SO_REUSEADDR);

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

Θέστε χρονικό όριο λήψης ώστε μια μπλοκαριστική recv ή ανάγνωση από την υποδοχή να επιστρέψει με EAGAIN / EWOULDBLOCK μετά από 5 δευτερόλεπτα αντί να κρεμάει για πάντα. Η τιμή της επιλογής είναι πακεταρισμένο struct timeval:

use Socket qw(SOL_SOCKET SO_RCVTIMEO);

my $tv = pack("l!l!", 5, 0);    # 5 seconds, 0 microseconds
setsockopt($sock, SOL_SOCKET, SO_RCVTIMEO, $tv)
    or die "SO_RCVTIMEO: $!";

Ενεργοποιήστε τα probes keepalive του TCP ώστε ημι-ανοιχτές συνδέσεις (κατέρρευσε ο ομότιμος, τραβήχτηκε το καλώδιο) να γίνονται τελικά αντιληπτές και η υποδοχή να σφάλλει αντί να μπλοκάρει επ” αόριστον:

use Socket qw(SOL_SOCKET SO_KEEPALIVE);

setsockopt($sock, SOL_SOCKET, SO_KEEPALIVE, 1)
    or die "SO_KEEPALIVE: $!";

Κάντε την close να μπλοκάρει για έως 10 δευτερόλεπτα ενώ ο πυρήνας εκκενώνει μη απεσταλμένα δεδομένα, και μετά να απορρίπτει και να κάνει reset. Το SO_LINGER παίρνει struct δύο ακεραίων: τη σημαία ενεργοποίησης και το χρονικό όριο σε δευτερόλεπτα:

use Socket qw(SOL_SOCKET SO_LINGER);

setsockopt($sock, SOL_SOCKET, SO_LINGER, pack("ii", 1, 10))
    or die "SO_LINGER: $!";

Μεγαλώστε τον ενταμιευτή λήψης του πυρήνα για υποδοχή μαζικής μεταφοράς. Ο πυρήνας τυπικά διπλασιάζει την τιμή που ζητάτε και την περιορίζει στο net.core.rmem_max:

use Socket qw(SOL_SOCKET SO_RCVBUF);

setsockopt($sock, SOL_SOCKET, SO_RCVBUF, 1 << 20)   # 1 MiB
    or die "SO_RCVBUF: $!";

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

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

  • Η σειρά έχει σημασία. Η SO_REUSEADDR πρέπει να τεθεί πριν την bind. Η SO_KEEPALIVE μπορεί να μπει πριν ή μετά την connect, αλλά για υποδοχές διακομιστή θέστε την στο αποδεκτό θυγατρικό filehandle που επιστρέφει η accept, όχι σε αυτό που ακούει - οι επιλογές δεν διαδίδονται πάντα.

  • Η συντομογραφία ακεραίου είναι pack("i", N), όχι pack("l", N). Σε πλατφόρμες όπου το int και το long διαφέρουν σε μέγεθος, το να περάσετε σκέτο ακέραιο και το να περάσετε pack("l", N) γράφουν διαφορετικό αριθμό bytes. Και τα δύο τυχαίνει να λειτουργούν για τις κοινές λογικές επιλογές μεγέθους int σε LP64 Linux, αλλά η συντομογραφία είναι η φορητή προεπιλογή.

  • Επιλογές με τιμή τύπου struct χρειάζονται ρητό pack. Οι SO_LINGER, SO_RCVTIMEO, SO_SNDTIMEO, IP_ADD_MEMBERSHIP, IP_MREQ, και παρόμοιες παίρνουν structs σταθερής διάταξης. Περάστε πακεταρισμένη συμβολοσειρά σωστού μήκους ή ο πυρήνας απορρίπτει την κλήση με EINVAL.

  • Το LEVEL επιλέγει τον χώρο ονομάτων της επιλογής. SOL_SOCKET για γενικές επιλογές, IPPROTO_TCP για ειδικές του TCP (TCP_NODELAY, TCP_KEEPIDLE), IPPROTO_IP για IPv4 (IP_TTL, IP_ADD_MEMBERSHIP), IPPROTO_IPV6 για IPv6. Αναντιστοιχία LEVEL και OPTNAME δίνει ENOPROTOOPT.

  • Επιλογές μόνο για ανάγνωση ή μη υποστηριζόμενες αποτυγχάνουν με ENOPROTOOPT. Αυτό ενεργοποιείται επίσης όταν ο πυρήνας απλώς δεν γνωρίζει την επιλογή - συνηθισμένο όταν αντιγράφεται κώδικας μεταξύ λειτουργικών συστημάτων.

  • Προνομιακές επιλογές. Λίγες επιλογές (SO_PRIORITY πάνω από κάποιες τιμές, IP_TRANSPARENT, SO_BINDTODEVICE) απαιτούν CAP_NET_ADMIN σε Linux· μια κλήση χωρίς προνόμια αποτυγχάνει με EPERM.

  • Η ανάγνωση πίσω γίνεται με την getsockopt, όχι με την setsockopt. Η setsockopt δεν έχει μορφή ερώτησης· χρησιμοποιήστε την getsockopt για να επιβεβαιώσετε τι πραγματικά αποθήκευσε ο πυρήνας (μπορεί να στρογγυλοποιήσει, να περικόψει ή να διπλασιάσει την τιμή).

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

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

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

  • getsockopt - ο αντίστοιχος ερώτησης· διαβάστε πίσω μια επιλογή για να δείτε τι πράγματι εφάρμοσε ο πυρήνας

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

  • bind - θέστε το SO_REUSEADDR με setsockopt πριν καλέσετε bind σε υποδοχή διακομιστή

  • accept - επιλογές που τίθενται στον listener δεν διαδίδονται όλες· εφαρμόστε ξανά τις επιλογές ανά σύνδεση στο αποδεκτό handle

  • pack - δομεί τη συμβολοσειρά bytes OPTVAL για επιλογές με τιμή τύπου struct όπως οι SO_LINGER και SO_RCVTIMEO

  • Socket - πηγή των SOL_SOCKET, IPPROTO_TCP, SO_REUSEADDR, TCP_NODELAY, και των υπολοίπων συμβολικών σταθερών