connect#
יוזם חיבור מסוקט לכתובת מרוחקת.
connect הוא החצי בצד הלקוח של לחיצת היד של הסוקט. בהינתן SOCKET שנוצר עם socket וכתובת ארוזה NAME בצורה שמשפחת הכתובות של הסוקט מצפה לה, הוא מבקש מהקרנל להקים חיבור לאותו עמית. זוהי עטיפה דקה מעל קריאת המערכת connect(2) ויורשת כל אחת מהסמנטיקות של אותה קריאה - חוסם, לא־חוסם, ושגיאה.
תקציר#
connect SOCKET, NAME
מה מקבלים בחזרה#
אמיתי (1) בהצלחה, שקרי בכישלון עם $! מוגדר לשגיאת המערכת. תמיד יש לבדוק את ערך ההחזרה - אין התנהגות שימושית של ברירת מחדל כאשר ניסיון חיבור נכשל:
connect($sock, $peer)
or die "connect to $host:$port failed: $!";
מצב גלובלי שהוא נוגע בו#
בניית NAME: זה struct ארוז, לא מחרוזת#
הארגומנט השני אינו מחרוזת "host:port". זהו sockaddr ארוז במבנה הבתים המדויק שהקרנל מצפה לו עבור משפחת הכתובות של הסוקט. יש לבנותו עם העזרים מ־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 לא־חוסם עם זמן־פסק באמצעות 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. הבייטים הארוזים נושאים את המשפחה; הקרנל בודק.כבר מחובר. קריאה ל־
connectעל סוקט זרם שכבר מחובר נכשלת עםEISCONN.סוקטים נטולי חיבור. על סוקטי
SOCK_DGRAM/SOCK_RAW,connectלא מחליף חבילות; הוא רושם עמית ברירת מחדל כדי שקריאותsend/recvעוקבות יוכלו להשמיט את הכתובת. ניתן לקרוא לו שוב עםNAMEחדש, או לאפסו על־ידי קריאה עם sockaddr שלAF_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- יוצר את ה־endpoint ש־connectפועל עליוbind- מקבע את הכתובת המקומית לפני החיבור; נדרש לעיתים נדירות בלקוחaccept- המקבילה בצד השרת שלconnectgetpeername- מחזיר את כתובת העמית של סוקט מחוברshutdown- סוגר כיוון אחד של סוקט מחובר מבלי לשחרר את ה־descriptorSocket- אורזים (sockaddr_in,sockaddr_un, …) וקבועים (PF_INET,SOCK_STREAM, …) המשמשים לבניית ארגומנטיםErrno- קבועים סימבוליים להשוואת$!כנגדEINPROGRESS,EISCONN,ECONNREFUSED, …