Υποδοχές (sockets)

socketpair#

Δημιουργεί ένα ανώνυμο, συνδεδεμένο ζεύγος υποδοχών που μιλούν μεταξύ τους.

Η socketpair ανοίγει δύο φρέσκα filehandles στα SOCKET1 και SOCKET2 ήδη συνδεδεμένα μεταξύ τους, οπότε ο,τιδήποτε γράφεται στο ένα βγαίνει από το άλλο. Καμία διεύθυνση, κανένα bind, κανένα listen, κανένα accept. Η συνηθέστερη χρήση είναι η επικοινωνία με παιδική διεργασία δημιουργημένη από fork - κάθε πλευρά κρατά ένα handle και κλείνει το άλλο με close.

Σύνοψη#

use Socket;
socketpair(SOCKET1, SOCKET2, DOMAIN, TYPE, PROTOCOL) or die $!;
socketpair(my $s1, my $s2, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die $!;

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

Αληθές σε επιτυχία, ψευδές σε αποτυχία (με ορισμένη την $!). Σε επιτυχία και τα δύο ορίσματα filehandle συμπληρώνονται με φρέσκα handles· σε αποτυχία μένουν άθικτα. Ελέγχετε πάντα την τιμή επιστροφής - κάθε συνδυασμός domain/type/protocol εξαρτάται από την πλατφόρμα.

socketpair(my $a, my $b, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
    or die "socketpair: $!";

Οι σταθερές DOMAIN, TYPE και PROTOCOL προέρχονται από το άρθρωμα Socket. Το AF_UNIX με SOCK_STREAM και PF_UNSPEC είναι η φορητή προεπιλογή.

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

  • Η $! ορίζεται σε αποτυχία στο errno του συστήματος.

  • $^F - ο μέγιστος περιγραφέας αρχείου συστήματος κάτω από τον οποίο το close-on-exec δεν τίθεται. Σε συστήματα με FD_CLOEXEC, οι περιγραφείς πάνω από την $^F αποκτούν αυτόματα close-on-exec· κάτω από αυτήν, επιβιώνουν στο exec. Η προεπιλογή είναι 2 (stdin/stdout/stderr). Αυξήστε την πριν την socketpair αν θέλετε τα νέα handles να κληρονομούνται κατά την exec.

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

Απλή σωλήνωση γονέα/παιδιού με socketpair ροής. Κάθε πλευρά κλείνει την άκρη που δεν χρειάζεται, ώστε το EOF να διαδίδεται σωστά:

use Socket;

socketpair(my $child, my $parent, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
    or die "socketpair: $!";

my $pid = fork // die "fork: $!";
if ($pid == 0) {
    close $child;
    print $parent "hello from child\n";
    close $parent;
    exit;
}
close $parent;
chomp(my $msg = <$child>);          # "hello from child"
waitpid $pid, 0;

Αμφίδρομη ροή: και οι δύο διεργασίες διαβάζουν και γράφουν στο ίδιο handle. Δεν χρειάζεται shutdown επειδή καμία πλευρά δεν κλείνει μια κατεύθυνση πρόωρα:

use Socket;

socketpair(my $a, my $b, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die $!;
my $pid = fork // die $!;
if ($pid == 0) {
    close $a;
    while (my $line = <$b>) {
        chomp $line;
        print $b "echo: $line\n";
    }
    exit;
}
close $b;
print $a "ping\n";
chomp(my $reply = <$a>);            # "echo: ping"
close $a;
waitpid $pid, 0;

Εξομοίωση της pipe με socketpair. Η shutdown μετατρέπει μια αμφίδρομη υποδοχή σε μονόδρομο κανάλι:

use Socket;
socketpair(my $rdr, my $wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die $!;
shutdown($rdr, 1);                  # reader cannot write
shutdown($wtr, 0);                  # writer cannot read

Ζεύγος datagram - τα μηνύματα διατηρούν τα όρια, οπότε μία recv επιστρέφει ακριβώς μία send:

use Socket;
socketpair(my $a, my $b, AF_UNIX, SOCK_DGRAM, PF_UNSPEC) or die $!;
send($a, "one", 0)   or die $!;
send($a, "two", 0)   or die $!;
recv($b, my $m1, 64, 0);            # "one"
recv($b, my $m2, 64, 0);            # "two"

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

  • Το AF_UNIX είναι το μόνο φορητό domain. Στα περισσότερα συστήματα η socketpair λειτουργεί μόνο με AF_UNIX· άλλες οικογένειες επιστρέφουν EAFNOSUPPORT. Χρησιμοποιήστε τη σταθερά, όχι σκληρά κωδικοποιημένο 1.

  • Έξοδος χωρίς ενταμίευση. Τα handles ροής socketpair ενταμιεύουν όπως κάθε άλλο filehandle. Θέστε την $| στον εγγραφέα (αφού τον επιλέξετε με select) αλλιώς ο αναγνώστης θα μπλοκάρει περιμένοντας έξοδο που βρίσκεται ακόμη στον ενταμιευτή του γονέα. Η autoflush από το IO::Handle είναι η συνήθης μορφή:

    $parent->autoflush(1);
    
  • Κλείστε και τις δύο άκρες αλλιώς το EOF δεν φτάνει ποτέ. Ένα socketpair ροής παραδίδει EOF σε αναγνώστη μόνο αφού κάθε εγγράψιμο αντίγραφο του handle του ομοτίμου κλείσει. Ένα παιδί που ξεχνά να κλείσει με close την άκρη του γονέα θα κρεμάσει τον γονέα στο <$handle> για πάντα.

  • Close-on-exec μέσω της $^F. Filehandles των οποίων ο αριθμητικός περιγραφέας είναι μεγαλύτερος της $^F αποκτούν FD_CLOEXEC σε πλατφόρμες που το υποστηρίζουν, οπότε εξαφανίζονται κατά την exec. Αυξήστε την $^F πριν την κλήση αν το handle πρέπει να επιβιώσει μιας exec.

  • Μη υλοποιημένη στην πλατφόρμα. Αν η υποκείμενη κλήση συστήματος socketpair(2) δεν υπάρχει, η perl εγείρει εξαίρεση αντί να επιστρέψει ψευδές. Παγιδέψτε την με eval αν χρειάζεστε υποχώρηση.

  • Datagram έναντι ροής. Το SOCK_STREAM είναι προσανατολισμένο σε bytes (χωρίς όρια μηνυμάτων, χρησιμοποιήστε framing με νέα γραμμή ή προθέματα μήκους). Το SOCK_DGRAM διατηρεί τα όρια μηνυμάτων αλλά τα χάνει σιωπηρά αν ο ενταμιευτής λήψης είναι μικρότερος από το μήνυμα.

  • PROTOCOL. Για AF_UNIX το πρωτόκολλο αγνοείται· το PF_UNSPEC0) είναι σύμβαση. Ο ορισμός πρωτοκόλλου που δεν ταιριάζει στον συνδυασμό domain/type επιστρέφει EPROTONOSUPPORT.

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

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

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

  • socket - δημιουργεί μία υποδοχή όταν μόνο η μία άκρη είναι δική σας (η άλλη έρχεται από το δίκτυο μέσω accept ή connect)

  • pipe - μονόδρομο κανάλι bytes· ελαφρύτερη από την socketpair αλλά δεν μπορεί να κάνει αμφίδρομη κίνηση σε μία κλήση

  • send / recv - I/O προσανατολισμένη σε μηνύματα, απαιτείται για socketpairs SOCK_DGRAM

  • fork - ο τυπικός σύντροφος: μία socketpair πριν το fork δίνει σε γονέα και παιδί έτοιμο αγωγό

  • Socket - πηγή των AF_UNIX, SOCK_STREAM, SOCK_DGRAM, PF_UNSPEC και των άλλων σταθερών που περιμένει η socketpair

  • $^F - κατώφλι πάνω από το οποίο νέοι περιγραφείς αποκτούν close-on-exec· έχει σημασία όταν τα handles πρέπει να επιβιώσουν μιας exec