Υποδοχές (sockets)

recv#

Διαβάζει ένα εισερχόμενο μήνυμα από υποδοχή σε βαθμωτό.

Η recv διαβάζει μέχρι LENGTH bytes από το SOCKET στο SCALAR, αντικαθιστώντας ό,τι κρατούσε προηγουμένως το SCALAR. Το SCALAR μεγαλώνει ή συρρικνώνεται στο πραγματικό πλήθος των bytes που ελήφθησαν. Το FLAGS είναι η ίδια μάσκα bits που δέχεται η υποκείμενη κλήση συστήματος recvfrom(2) - 0 για συνηθισμένες αναγνώσεις· οι συνηθισμένες μη μηδενικές τιμές είναι MSG_PEEK (κοίταγμα χωρίς κατανάλωση), MSG_WAITALL (μπλοκάρισμα μέχρι να φτάσουν LENGTH bytes), και MSG_DONTWAIT (ποτέ μπλοκάρισμα). Για υποδοχή χωρίς σύνδεση η recv επιστρέφει την πακεταρισμένη διεύθυνση του αποστολέα· για συνδεδεμένη υποδοχή επιστρέφει την κενή συμβολοσειρά. Στο παρασκήνιο αυτό είναι η recvfrom(2), όχι η recv(2).

Σύνοψη#

recv SOCKET, SCALAR, LENGTH, FLAGS

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

  • Σε επιτυχία από υποδοχή χωρίς σύνδεση (UDP, UNIX datagram): η διεύθυνση του αποστολέα ως πακεταρισμένη συμβολοσειρά sockaddr. Κάντε unpack με τις sockaddr_in, sockaddr_in6 ή sockaddr_un του Socket ανάλογα με την οικογένεια διευθύνσεων.

  • Σε επιτυχία από συνδεδεμένη υποδοχή (TCP, συνδεδεμένο UDP): η κενή συμβολοσειρά "". Η κενή συμβολοσειρά είναι αληθής για τον έλεγχο ορισμένου-έναντι-undef αλλά ψευδής σε λογικό περιβάλλον - ελέγξτε με defined, όχι με απλή αληθοφάνεια.

  • Σε σφάλμα: undef, με το $! ρυθμισμένο στο errno από την αποτυχημένη κλήση recvfrom(2). Τυπικά σφάλματα: EAGAIN / EWOULDBLOCK σε μη μπλοκαριστική υποδοχή χωρίς δεδομένα έτοιμα, ECONNRESET σε επαναφορά TCP ομότιμου, EBADF σε κλειστό handle.

Το SCALAR πάντα αλλάζει μέγεθος στο πλήθος bytes που διαβάστηκε. Ανάγνωση μηδέν bytes σε συνδεδεμένη υποδοχή ροής σημαίνει ότι ο ομότιμος έκλεισε καθαρά την πλευρά εγγραφής του - η recv επιστρέφει "" και το SCALAR γίνεται η κενή συμβολοσειρά.

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

  • Το $! τίθεται σε σφάλμα στο errno του συστήματος.

  • Καμία άλλη ειδική μεταβλητή δεν εμπλέκεται. Η recv δεν τηρεί τις $/, $,, ή $\ - αυτές είναι έννοιες I/O προσανατολισμένες σε γραμμές και η recv είναι πρωτογενής λειτουργία ακατέργαστων datagrams / ροής bytes.

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

Ανάγνωση ενός UDP datagram και αναγνώριση του αποστολέα:

use Socket;
my $from = recv($sock, my $buf, 1500, 0)
    or die "recv: $!";
my ($port, $ip) = sockaddr_in($from);
print "got ", length($buf), " bytes from ",
      inet_ntoa($ip), ":$port\n";

Ανάγνωση από συνδεδεμένη υποδοχή TCP. Η διεύθυνση αποστολέα είναι κενή, οπότε ελέγξτε με defined αντί για λογική αλήθεια:

defined(recv($sock, my $buf, 4096, 0))
    or die "recv: $!";
# $buf now holds 0..4096 bytes; 0 means the peer closed.

Κοιτάξτε το επόμενο datagram χωρίς να το καταναλώσετε. Η δεύτερη κλήση επιστρέφει τα ίδια bytes:

use Socket;
recv($sock, my $peek,    1500, MSG_PEEK) or die $!;
recv($sock, my $consume, 1500, 0)        or die $!;
# $peek and $consume hold the same datagram.

Βρόχος μη μπλοκαριστικής ανάγνωσης. Το EAGAIN / EWOULDBLOCK είναι το φυσιολογικό σήμα «δεδομένα ακόμα όχι», όχι πραγματικό σφάλμα:

use Errno qw(EAGAIN EWOULDBLOCK);
while (1) {
    my $from = recv($sock, my $buf, 1500, 0);
    unless (defined $from) {
        last if $! == EAGAIN || $! == EWOULDBLOCK;
        die "recv: $!";
    }
    handle_datagram($from, $buf);
}

Επιβολή ανάγνωσης πλήρους μήκους σε υποδοχή ροής που ενδέχεται να κατατμήσει το μήνυμα - το MSG_WAITALL μπλοκάρει μέχρι να φτάσουν LENGTH bytes ή να πεθάνει η σύνδεση:

use Socket;
defined(recv($sock, my $frame, 64, MSG_WAITALL))
    or die "recv: $!";
# $frame is exactly 64 bytes, or the peer closed early.

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

  • Υποδοχή με στρώμα UTF-8: αν το SOCKET έχει στρώμα :utf8 (απευθείας ή μέσω :encoding(...)), η recv ρίχνει εξαίρεση. Η recv είναι προσανατολισμένη σε bytes και δεν αλληλεπιδρά με στρώματα PerlIO· χρησιμοποιήστε binmode για να αφαιρέσετε το στρώμα πριν την ανάγνωση, ή αποκωδικοποιήστε τα αποτελούμενα bytes μόνοι σας.

  • LENGTH έναντι μεγέθους datagram: για υποδοχές datagram, αν το LENGTH είναι μικρότερο από το εισερχόμενο datagram, το πλεόνασμα απορρίπτεται σιωπηλά. Διαστασιολογήστε τον ενταμιευτή στο MTU του πρωτοκόλλου (τυπικά 1500 για UDP πάνω από Ethernet, 65507 για το μέγιστο IPv4 UDP).

  • Η επιστροφή "" δεν είναι αρκετά ψευδής: η recv σε συνδεδεμένη υποδοχή επιστρέφει την κενή συμβολοσειρά, την οποία το ! αντιμετωπίζει ως ψευδή. Κώδικας όπως recv(...) or die $! πεθαίνει σε κάθε επιτυχή συνδεδεμένη ανάγνωση. Χρησιμοποιήστε defined:

    defined(recv($sock, $buf, $len, 0)) or die "recv: $!";
    
  • Αποτέλεσμα μηδέν bytes σε υποδοχή ροής: η recv επιστρέφει "" και το SCALAR γίνεται κενό όταν ο ομότιμος έχει κάνει ομαλό κλείσιμο. Διακρίνετε το τέλος ροής από πραγματικό σφάλμα ελέγχοντας length($buf) == 0 μετά από ορισμένη επιστροφή.

  • Σήματα: μια μπλοκαριστική recv που διακόπτεται από σήμα επιστρέφει undef με $! == EINTR. Επαναλάβετε ή εγκαταστήστε κατάλληλη sigaction με SA_RESTART αν αυτό δεν είναι αυτό που θέλετε.

  • Κλειστή υποδοχή: η recv σε κλειστό ή ποτέ-ανοιχτό handle επιστρέφει undef, θέτει το $! σε EBADF, και εκπέμπει προειδοποίηση recv() on closed socket υπό use warnings.

  • Το προϋπάρχον περιεχόμενο του SCALAR καταστρέφεται. Η recv δεν προσαρτά· αντικαθιστά. Χρησιμοποιήστε φρέσκο λεξιλογικό ή καθαρίστε το βαθμωτό πριν από κάθε κλήση.

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

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

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

  • send - η πλευρά εγγραφής της ίδιας υποδοχής· ίδιο λεξιλόγιο FLAGS, ίδια διάκριση χωρίς σύνδεση έναντι συνδεδεμένης

  • socket - δημιουργία του handle SOCKET από το οποίο διαβάζει η recv

  • bind - απαιτείται πριν την recv σε υποδοχή datagram πλευράς διακομιστή ώστε ο πυρήνας να γνωρίζει σε ποια θύρα να παραδώσει

  • connect - όταν χρησιμοποιείται σε υποδοχή datagram, κάνει την recv να επιστρέφει "" όπως σε υποδοχή ροής και φιλτράρει datagrams από άλλους ομότιμους

  • sysread - ανάγνωση σε επίπεδο bytes για υποδοχές ροής όταν δεν χρειάζεστε τη διεύθυνση αποστολέα· ενσωματώνεται σε βρόχους βασισμένους σε select

  • Socket - sockaddr_in, inet_ntoa, MSG_PEEK, MSG_WAITALL, και οι υπόλοιπες σταθερές που καταναλώνει η recv