*[Υποδοχές (sockets)](../perlfunc-by-category.md)* # accept Αποδοχή εισερχόμενης σύνδεσης σε μια υποδοχή που ακούει. Η `accept` αποτελεί τη διακομιστική πλευρά της χειραψίας σύνδεσης. Περιμένει στο `GENERICSOCKET` — μια υποδοχή που έχει ήδη δημιουργηθεί με [`socket`](socket.md), συνδεθεί με [`bind`](bind.md) και τεθεί σε κατάσταση ακρόασης με [`listen`](listen.md) — μέχρι να συνδεθεί ένας πελάτης, οπότε εγκαθιστά μια ολοκαίνουρια συνδεδεμένη υποδοχή στο `NEWSOCKET` και επιστρέφει την πακεταρισμένη διεύθυνση του πελάτη. Το `GENERICSOCKET` παραμένει σε κατάσταση ακρόασης, έτοιμο για την επόμενη κλήση. Η συμπεριφορά αντικατοπτρίζει την κλήση συστήματος POSIX `accept(2)`. ## Σύνοψη ```perl accept NEWSOCKET, GENERICSOCKET ``` ## Τι επιστρέφεται Η διεύθυνση του πελάτη στην πακεταρισμένη μορφή που χρησιμοποιείται από την οικογένεια διευθύνσεων του `GENERICSOCKET` — η ίδια μορφή που θα περνούσατε στη [`connect`](connect.md) ή θα αποπακετάρατε με [`Socket::unpack_sockaddr_in`](../../Socket/unpack_sockaddr_in.md) για IPv4, ή με `Socket::unpack_sockaddr_in6` / `unpack_sockaddr_un` για IPv6 και υποδοχές πεδίου Unix αντίστοιχα. Σε αποτυχία επιστρέφει ψευδή τιμή (την κενή συμβολοσειρά) και θέτει την [`$!`](../perlvar.md) στο υποκείμενο `errno`. Το `NEWSOCKET` συμπληρώνεται ως παρενέργεια — είναι ένα απλό όρισμα filehandle, όχι τιμή επιστροφής. Μια bareword όπως το `CLIENT` αυτο-δημιουργεί ένα typeglob· ένα λεκτικό filehandle όπως το `my $client` συμπληρώνεται επιτόπου: ```perl my $client; accept($client, $server) or die "accept: $!"; # $client is now a readable/writable handle to the connected peer ``` ## Καθολική κατάσταση που επηρεάζει - [`$!`](../perlvar.md) — τίθεται σε αποτυχία στο υποκείμενο `errno` (`EINTR`, `EAGAIN`/`EWOULDBLOCK` σε μη μπλοκαριστικές υποδοχές ακρόασης, `ECONNABORTED`, `EMFILE`, `ENFILE`). - [`$^F`](../perlvar.md) — ο μέγιστος περιγραφέας αρχείου του συστήματος. Σε συστήματα που υποστηρίζουν τη σημαία close-on-exec, η `accept` θέτει `FD_CLOEXEC` στον νέο περιγραφέα όταν ο αριθμός του είναι μεγαλύτερος από το `$^F` (προεπιλογή `2`, καλύπτοντας τα τυπικά ρεύματα). Αυξήστε το `$^F` πριν την `accept` αν θέλετε η υποδοχή που έγινε αποδεκτή να επιβιώσει της [`exec`](exec.md). ## Παραδείγματα Ελάχιστος βρόχος αποδοχής τύπου TCP echo: ```perl use Socket; socket(my $server, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die "socket: $!"; bind($server, sockaddr_in(8080, INADDR_ANY)) or die "bind: $!"; listen($server, SOMAXCONN) or die "listen: $!"; while (my $peer = accept(my $client, $server)) { my ($port, $iaddr) = sockaddr_in($peer); print $client "hello ", inet_ntoa($iaddr), ":$port\n"; close $client; } die "accept: $!"; # loop exits only on error ``` Αποπακετάρισμα της επιστρεφόμενης διεύθυνσης για καταγραφή: ```perl use Socket; my $peer = accept(my $client, $server) or die "accept: $!"; my ($port, $iaddr) = sockaddr_in($peer); printf "connection from %s port %d\n", inet_ntoa($iaddr), $port; ``` Μη μπλοκαριστική `accept`. Θέστε πρώτα το `$server` σε μη μπλοκαριστική κατάσταση· μια κλήση χωρίς εκκρεμή σύνδεση επιστρέφει τότε ψευδή τιμή με την [`$!`](../perlvar.md) σε `EAGAIN` ή `EWOULDBLOCK`: ```perl use Errno qw(EAGAIN EWOULDBLOCK); use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); my $flags = fcntl($server, F_GETFL, 0); fcntl($server, F_SETFL, $flags | O_NONBLOCK); my $peer = accept(my $client, $server); if (!$peer) { if ($! == EAGAIN || $! == EWOULDBLOCK) { # no pending connection — try again later } else { die "accept: $!"; } } ``` Διατηρήστε την αποδεκτή υποδοχή κατά τη διάρκεια της [`exec`](exec.md) αυξάνοντας το [`$^F`](../perlvar.md) ώστε ο χρόνος εκτέλεσης να μη θέσει `FD_CLOEXEC`: ```perl local $^F = 10_000; accept(my $client, $server) or die "accept: $!"; exec "/usr/libexec/handler", fileno($client); ``` ## Οριακές περιπτώσεις - **Το `GENERICSOCKET` δεν ακούει** — η `accept` αποτυγχάνει με την [`$!`](../perlvar.md) σε `EINVAL`. Καλέστε πρώτα την [`listen`](listen.md) στην υποδοχή του διακομιστή. - **Το `NEWSOCKET` είναι ήδη ανοιχτό** — η υπάρχουσα λαβή κλείνει σιωπηλά πριν εγκατασταθεί ο νέος περιγραφέας, ακριβώς όπως στις [`open`](open.md) και [`socket`](socket.md). Αν η παλιά λαβή ήταν η μόνη αναφορά σε ένα ρεύμα με ενταμιευτή, τυχόν μη εκκενωμένα δεδομένα χάνονται. Κλείστε τη ρητά εκ των προτέρων όταν αυτό έχει σημασία. - **Σήμα κατά την κλήση** — ένα σήμα που παραδίδεται ενώ η `accept` είναι μπλοκαρισμένη κάνει την υποκείμενη κλήση συστήματος να επιστρέψει `EINTR`. Το pperl δεν επανεκκινεί αυτόματα: η `accept` επιστρέφει ψευδή τιμή και αφήνει την `$!` σε `EINTR`. Τυλίξτε σε βρόχο επανάληψης αν οι χειριστές σημάτων σας δεν τερματίζουν τη διεργασία. - **Εξάντληση περιγραφέων** — το `EMFILE` (όριο διεργασίας) ή το `ENFILE` (όριο συστήματος) σε έναν φορτωμένο διακομιστή είναι ο συνηθισμένος λόγος που η `accept` αρχίζει να αποτυγχάνει υπό φορτίο. Αντιμετωπίστε τα ως παροδικά· κλείστε αδρανείς πελάτες και ξαναδοκιμάστε. - **Αναντιστοιχία οικογένειας διευθύνσεων στην πακεταρισμένη επιστροφή** — ο πακεταρισμένος ενταμιευτής ακολουθεί την οικογένεια του `GENERICSOCKET`. Το αποπακετάρισμα μιας διεύθυνσης πεδίου Unix με [`Socket::unpack_sockaddr_in`](../../Socket/unpack_sockaddr_in.md) παράγει σκουπίδια. Παρακολουθήστε εσείς την οικογένεια ή χρησιμοποιήστε την [`Socket::sockaddr_family`](../../Socket/sockaddr_family.md) για να γίνει η αποστολή. - **Οι παρενθέσεις είναι προαιρετικές, τα κόμματα όχι** — τα `accept $c, $s` και `accept($c, $s)` λειτουργούν και τα δύο· το `accept $c $s` είναι συντακτικό σφάλμα. - **Περιβάλλον λίστας έναντι βαθμωτού** — η πακεταρισμένη διεύθυνση επιστροφής είναι συμβολοσειρά bytes· το περιβάλλον λίστας **δεν** την επεκτείνει σε `(port, addr)`. Καλέστε την `sockaddr_in` / αντίστοιχη για αποπακετάρισμα. ## Διαφορές από το upstream Πλήρως συμβατό με το upstream Perl 5.42. ## Δείτε επίσης - [`socket`](socket.md) — δημιουργεί την υποδοχή διακομιστή την οποία περιμένει η `accept` - [`bind`](bind.md) — προσαρτά την υποδοχή διακομιστή σε τοπική διεύθυνση πριν τις [`listen`](listen.md) και `accept` - [`listen`](listen.md) — υποχρεωτικό βήμα μεταξύ της [`bind`](bind.md) και της `accept`· καθορίζει το βάθος της ουράς εκκρεμοτήτων - [`connect`](connect.md) — το αντίστοιχο της πλευράς πελάτη· η `accept` επιστρέφει τη διεύθυνση που έδωσε μια κλήση `connect` - [`getpeername`](getpeername.md) — ανακτά την ίδια πακεταρισμένη διεύθυνση αργότερα από το ίδιο το `NEWSOCKET` - [`Socket`](../../Socket.md) — οι σταθερές (`PF_INET`, `SOCK_STREAM`, `INADDR_ANY`) και οι packers (`sockaddr_in`, `unpack_sockaddr_in`) που μετατρέπουν την πακεταρισμένη τιμή επιστροφής σε κάτι αξιοποιήσιμο - [`$^F`](../perlvar.md) — κατώφλι που ελέγχει το αν η `accept` θέτει `FD_CLOEXEC` στον νέο περιγραφέα