connect#
Ξεκινά μια σύνδεση από μια υποδοχή προς μια απομακρυσμένη διεύθυνση.
Η connect είναι το μισό από την πλευρά του πελάτη στην χειραψία της υποδοχής. Δοθέντος ενός SOCKET που δημιουργήθηκε με socket και μιας πακεταρισμένης διεύθυνσης NAME στη μορφή που αναμένει η οικογένεια διευθύνσεων της υποδοχής, ζητάει από τον πυρήνα να εγκαθιδρύσει σύνδεση με τον συγκεκριμένο ομότιμο. Είναι λεπτό περιτύλιγμα γύρω από την κλήση συστήματος connect(2) και κληρονομεί κάθε σημασιολογία μπλοκαρίσματος, μη μπλοκαρίσματος και σφάλματος αυτής της κλήσης.
Σύνοψη#
connect SOCKET, NAME
Τι επιστρέφεται#
Αληθές (1) σε επιτυχία, ψευδές σε αποτυχία με την $! τεθειμένη στο σφάλμα του συστήματος. Ελέγχετε πάντα την τιμή επιστροφής - δεν υπάρχει χρήσιμη προεπιλεγμένη συμπεριφορά όταν αποτυγχάνει μια απόπειρα σύνδεσης:
connect($sock, $peer)
or die "connect to $host:$port failed: $!";
Καθολική κατάσταση που επηρεάζει#
Η
$!τίθεται στοerrnoτου πυρήνα σε αποτυχία. Ερμηνεύστε την έναντι των σταθερών τηςErrno, όχι μέσω της τιμής συμβολοσειράς - το μηνύμα μετά τη μετατροπή σε συμβολοσειρά εξαρτάται από το locale.Το ίδιο το handle της υποδοχής φέρει την κατάσταση της σύνδεσης· καμία άλλη ειδική μεταβλητή δεν εμπλέκεται.
Δόμηση του NAME: είναι ένα πακεταρισμένο struct, όχι συμβολοσειρά#
Το δεύτερο όρισμα δεν είναι συμβολοσειρά "host:port". Είναι ένα πακεταρισμένο sockaddr στην ακριβή διάταξη bytes που αναμένει ο πυρήνας για την οικογένεια διευθύνσεων της υποδοχής. Δομήστε το με τους βοηθούς από την Socket:
sockaddr_in($port, $inaddr)για IPv4 - η$inaddrαπό τηνinet_atonή τηνinet_pton.sockaddr_in6($port, $in6addr)για IPv6 - η$in6addrαπό τηνinet_pton(AF_INET6, ...).sockaddr_un($path)για υποδοχές τομέα Unix.
Το χειροκίνητο πακετάρισμα με την pack λειτουργεί, αλλά δεν υπάρχει λόγος να το κάνετε όταν η Socket εξάγει ήδη τους κατάλληλους κατασκευαστές.
Παραδείγματα#
Ένας απλός πελάτης TCP πάνω σε IPv4:
use Socket;
socket(my $sock, PF_INET, SOCK_STREAM, getprotobyname("tcp"))
or die "socket: $!";
my $addr = sockaddr_in(80, inet_aton("93.184.216.34"));
connect($sock, $addr)
or die "connect: $!";
print $sock "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
Σύγχρονος πελάτης ανεξαρτήτως οικογένειας διευθύνσεων μέσω getaddrinfo:
use Socket qw(getaddrinfo SOCK_STREAM);
my ($err, @res) = getaddrinfo("example.com", "80",
{ socktype => SOCK_STREAM });
die "getaddrinfo: $err" if $err;
my $sock;
for my $ai (@res) {
socket($sock, $ai->{family}, $ai->{socktype}, $ai->{protocol})
or next;
last if connect($sock, $ai->{addr});
close $sock;
undef $sock;
}
defined $sock or die "could not connect to any address";
Ένας πελάτης τομέα Unix:
use Socket;
socket(my $sock, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
connect($sock, sockaddr_un("/tmp/my.sock"))
or die "connect: $!";
Connect χωρίς μπλοκάρισμα με timeout μέσω select - ο ιδιωματικός τρόπος να βάλετε φραγή σε μια απόπειρα connect σε καθαρή Perl:
use Socket;
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
use Errno qw(EINPROGRESS);
socket(my $sock, PF_INET, SOCK_STREAM, 0) or die "socket: $!";
my $flags = fcntl($sock, F_GETFL, 0);
fcntl($sock, F_SETFL, $flags | O_NONBLOCK);
my $ok = connect($sock, sockaddr_in(80, inet_aton("93.184.216.34")));
if (!$ok && $! == EINPROGRESS) {
my $w = '';
vec($w, fileno($sock), 1) = 1;
my $n = select(undef, $w, undef, 5.0); # 5-second timeout
$n > 0 or die "connect timed out";
# Check SO_ERROR to see whether the async connect succeeded:
my $err = unpack("i", getsockopt($sock, SOL_SOCKET, SO_ERROR));
$err == 0 or die "connect: " . do { local $! = $err; "$!" };
}
Οριακές περιπτώσεις#
Αναντιστοιχία οικογένειας διευθύνσεων. Αν το
NAMEπακεταρίστηκε για διαφορετική οικογένεια από αυτή με την οποία δημιουργήθηκε η υποδοχή (π.χ.sockaddr_inέναντι υποδοχήςPF_INET6), ηconnectαποτυγχάνει μεEAFNOSUPPORTήEINVAL. Τα πακεταρισμένα bytes φέρουν την οικογένεια· ο πυρήνας ελέγχει.Ήδη συνδεδεμένη. Η κλήση
connectσε υποδοχή ροής που είναι ήδη συνδεδεμένη αποτυγχάνει μεEISCONN.Υποδοχές χωρίς σύνδεση. Σε υποδοχές
SOCK_DGRAM/SOCK_RAW, ηconnectδεν ανταλλάσσει πακέτα· καταγράφει έναν προεπιλεγμένο ομότιμο ώστε οι επόμενες κλήσειςsend/recvνα μπορούν να παραλείψουν τη διεύθυνση. Μπορεί να ξανακληθεί με νέοNAME, ή να εκκαθαριστεί καλώντας τη με sockaddrAF_UNSPEC.Υποδοχές χωρίς μπλοκάρισμα. Αν η υποδοχή είναι σε λειτουργία χωρίς μπλοκάρισμα, ένα connect TCP συνήθως επιστρέφει ψευδές με την
$!τεθειμένη σεEINPROGRESS. Η σύνδεση δεν έχει ακόμα εγκαθιδρυθεί. Περιμένετε να γίνει η υποδοχή εγγράψιμη (μέσωselectή του βρόχου συμβάντων σας), και μετά διαβάστε τοSO_ERRORμε τηνgetsockoptγια να λάβετε την τελική κατάσταση. ΈναSO_ERRORίσο με μηδέν σημαίνει ότι η σύνδεση είναι επάνω· οτιδήποτε άλλο είναι ο πραγματικός κωδικός αποτυχίας.Σήματα που διακόπτουν την κλήση. Μια μπλοκαριστική
connectμπορεί να επιστρέψει ψευδές με την$!τεθειμένη σεEINTRαν εκτελέστηκε χειριστής σήματος. Η υποδοχή εξακολουθεί να συνδέεται στο παρασκήνιο· πρέπει να περιμένετε στην εγγραψιμότητα και να ελέγξετε τοSO_ERRORόπως στην περίπτωση χωρίς μπλοκάρισμα - μην ξαναπροσπαθήσετε την κλήσηconnect, αυτό παράγειEALREADY.Μη δεσμευμένη διεύθυνση προέλευσης. Αν δεν έχει κληθεί πρώτα η
bind, ο πυρήνας επιλέγει διεύθυνση προέλευσης και εφήμερη θύρα αυτόματα. Η συνηθισμένη περίπτωση είναι να παραλείπεται ηbindστον πελάτη.Κλεισμένη ή μη ανοιγμένη υποδοχή. Αποτυγχάνει με
EBADF.
Διαφορές από το upstream#
Πλήρως συμβατό με το upstream Perl 5.42.
Δείτε επίσης#
socket- δημιουργεί το άκρο επί του οποίου λειτουργεί ηconnectbind- καρφώνει την τοπική διεύθυνση πριν τη σύνδεση· σπάνια χρειάζεται σε πελάτηaccept- ο αντίστοιχος τηςconnectαπό την πλευρά του διακομιστήgetpeername- ανακτά τη διεύθυνση του ομότιμου μιας συνδεδεμένης υποδοχήςshutdown- κλείνει τη μία κατεύθυνση μιας συνδεδεμένης υποδοχής χωρίς να απελευθερώνει τον περιγραφέαSocket- packers (sockaddr_in,sockaddr_un, …) και σταθερές (PF_INET,SOCK_STREAM, …) που χρησιμοποιούνται για τη δόμηση ορισμάτωνErrno- συμβολικές σταθερές για σύγκριση της$!έναντιEINPROGRESS,EISCONN,ECONNREFUSED, …