recv#
קריאת הודעה נכנסת מסוקט לתוך סקלר.
recv קורא עד LENGTH בתים מ־SOCKET לתוך SCALAR, ומחליף את מה ש־SCALAR החזיק קודם לכן. SCALAR גדל או מתכווץ למספר הבתים שהתקבלו בפועל. FLAGS הוא אותה מסיכת ביטים שקריאת המערכת הבסיסית recvfrom(2) מקבלת - 0 לקריאות רגילות; הערכים השונים מ־0 הנפוצים הם MSG_PEEK (להציץ מבלי לצרוך), MSG_WAITALL (לחסום עד שיגיעו LENGTH בתים), ו־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 מחובר): המחרוזת הריקה
"". המחרוזת הריקה היא אמת עבור הבדיקה defined־מול־undef אך שקר בהקשר בוליאני - בדקו עםdefined, לא אמיתיוּת פשוטה.בשגיאה:
undef, כאשר$!מוגדר ל־errnoמקריאתrecvfrom(2)הכושלת. שגיאות אופייניות:EAGAIN/EWOULDBLOCKבסוקט לא־חוסם ללא נתונים מוכנים,ECONNRESETבאיפוס עמית TCP,EBADFבמטפל סגור.
SCALAR תמיד משונה גודלו למספר הבתים שנקראו. קריאת אפס־בתים בסוקט זרם מחובר משמעה שהעמית סגר נקיות את צד הכתיבה שלו - recv מחזיר "" ו־SCALAR הופך למחרוזת הריקה.
מצב גלובלי שהוא נוגע בו#
דוגמאות#
קריאת datagram UDP אחד וזיהוי השולח:
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 הבא מבלי לצרוך אותו. הקריאה השנייה מחזירה את אותם בתים:
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 בתים נכנסים או שהחיבור מת:
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הוא מוכוון־בתים ואינו מתממשק עם שכבות PerlIO; השתמשו ב־binmodeלהסרת השכבה לפני הקריאה, או פענחו את הבתים שמתקבלים בעצמכם.LENGTH מול גודל ה־datagram: עבור סוקטי datagram, אם
LENGTHקטן מה־datagram הנכנס, העודף מושלך בשקט. סדרו את ה־buffer לגודל ה־MTU של הפרוטוקול (בדרך כלל 1500 עבור UDP על Ethernet, 65507 עבור המקסימום של UDP ב־IPv4).ערך ההחזרה
""אינו ״שקרי־דיו״:recvבסוקט מחובר מחזיר את המחרוזת הריקה, ש־!מתייחס אליה כשקר. קוד כמוrecv(...) or die $!מת על כל קריאת מחובר מוצלחת. השתמשו ב־defined:defined(recv($sock, $buf, $len, 0)) or die "recv: $!";
תוצאת אפס־בתים בסוקט זרם:
recvמחזיר""ו־SCALARהופך לריק כאשר העמית ביצע shutdown מסודר. הבחינו בין סוף־זרם לשגיאה אמיתית על־ידי בדיקתlength($buf) == 0אחרי החזרה מוגדרת.אותות:
recvחוסם שמופרע על־ידי אות מחזירundefכאשר$!==EINTR. נסו שוב או התקינוsigactionכראוי עםSA_RESTARTאם זה לא מה שרציתם.סוקט סגור:
recvעל מטפל סגור או שמעולם לא נפתח מחזירundef, מגדיר את$!ל־EBADF, ופולט אזהרתrecv() on closed socketתחתuse warnings.תוכן
SCALARקיים נהרס.recvאינו מצרף; הוא דורס. השתמשו בלקסיקל חדש או נקו את הסקלר לפני כל קריאה.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
send- צד הכתיבה של אותו סוקט; אותו אוצר־מילים שלFLAGS, אותה הבחנה חסר־חיבור־מול־מחוברsocket- יצירת מטפל ה־SOCKETש־recvקורא ממנוbind- נדרש לפניrecvבסוקט datagram בצד שרת כדי שהקרנל ידע לאיזה פורט למסורconnect- בעת שימוש בסוקט datagram, גורם ל־recvלהחזיר""כמו סוקט זרם ומסנן datagram־ים מעמיתים אחריםsysread- קריאה ברמת בתים עבור סוקטי זרם כאשר לא נחוצה כתובת השולח; משתלב בלולאות מבוססותselectSocket-sockaddr_in,inet_ntoa,MSG_PEEK,MSG_WAITALL, ויתר הקבועים ש־recvצורך