shutdown#
סגירת כיוון אחד של חיבור סוקט, או של שניהם.
shutdown אומר לקרנל להפסיק סוקט לבצע קריאות נוספות, כתיבות נוספות, או שניהם - בלי לסגור את ה־file descriptor. בניגוד ל־close, האפקט מיידי ומתפשט דרך כל עותק שנעשה לו fork של ה־descriptor, לא רק זה של תהליך זה. ל־HOW יש אותה משמעות כמו לארגומנט של קריאת המערכת shutdown(2).
תקציר#
shutdown SOCKET, HOW
מה מקבלים בחזרה#
1 בהצלחה. בכישלון, undef אם SOCKET אינו מטפל קובץ תקף, או 0 עם $! מוגדר לכל שגיאה אחרת (הסוקט אינו מחובר, כבר נסגר באותו כיוון, וכו«).
שתי החזרות כישלון נבדלות, לכן בדיקה תלת־כיוונית נחוצה לפעמים:
my $r = shutdown($sock, 1);
if (!defined $r) { die "bad filehandle" }
elsif (!$r) { die "shutdown failed: $!" }
הארגומנט HOW#
HOW הוא מספר שלם קטן התואם את הקבועים SHUT_* של POSIX:
0- להפסיק לקרוא. העמית עדיין יכול לשלוח, אך הנתונים יושלכו על־ידי הקרנל ו־read/sysreadבקצה זה יחזיר end-of-file.1- להפסיק לכתוב. פלט בתור נשטף, ואז העמית רואה end-of-file בצד הקריאה שלו.print/syswriteבקצה זה ייכשל ויעלהSIGPIPE.2- להפסיק את שני הכיוונים. שווה־ערך לקריאה ל־shutdownעם0ואז1.
השמות הסימבוליים SHUT_RD, SHUT_WR, SHUT_RDWR נמצאים ב־Socket אם מעדיפים קוד קריא:
use Socket qw(SHUT_WR);
shutdown $sock, SHUT_WR;
shutdown מול close#
close משחרר את ה־file descriptor בתהליך הנוכחי בלבד. תהליכים אחרים שירשו את ה־descriptor דרך fork שומרים על העותקים שלהם פתוחים, והעמית אינו רואה end-of-file עד שהעותק האחרון נסגר.
shutdown פועל על הסוקט שבבסיס, לא על ה־descriptor. לאחר shutdown($sock, 1) כל עותק שנעשה לו fork רואה את חצי הכתיבה סגור והעמית קורא end-of-file מיד - למרות שה־descriptor עצמו עדיין פתוח ועדיין ניתן לקרוא ממנו.
זוהי הסיבה הרגילה לפנות ל־shutdown: הורה וילד חולקים סוקט, הילד סיים לשלוח, וההורה חייב להמשיך לקרוא תשובות. close בילד היה בלתי־נראה לעמית; shutdown($sock, 1) אינו.
חצי־סגירה עבור פרוטוקולי בקשה/תגובה#
לקוח השולח בקשה מלאה ולאחר מכן צריך שהשרת ידע שאין יותר קלט משתמש ב־shutdown עם HOW = 1:
use IO::Socket::INET;
my $sock = IO::Socket::INET->new(PeerAddr => "example.com:80")
or die "connect: $!";
print $sock "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
shutdown $sock, 1; # signal end-of-request to the server
while (my $line = <$sock>) {
print $line;
}
close $sock;
ללא ה־shutdown, שרתים הקוראים עד end-of-input ייחסמו בהמתנה לנתוני בקשה נוספים.
דוגמאות#
להפסיק לקרוא אך להמשיך לכתוב - העמית יכול להמשיך לשלוח, פשוט לא נסתכל בזה:
shutdown $sock, 0;
להפסיק לכתוב, להמשיך לקרוא - חצי־סגירה טיפוסית לאחר סיום בקשה:
shutdown $sock, 1;
shutdown מלא, ואז סגירת ה־descriptor:
shutdown $sock, 2;
close $sock;
שימוש בקבועי Socket למען קריאוּת:
use Socket qw(SHUT_RD SHUT_WR SHUT_RDWR);
shutdown $sock, SHUT_WR;
בדיקת השגיאה הספציפית כאשר shutdown נכשל בכיוון שכבר סגור:
unless (shutdown $sock, 1) {
warn "shutdown write failed: $!";
}
מקרי קצה#
כתיבה לאחר
shutdown($sock, 1)נכשלת ומעלהSIGPIPE. פעולת ברירת המחדל מסיימת את התהליך; יש להתקין$SIG{PIPE} = 'IGNORE'(או מטפל) כדי להמיר זאת לכישלון כתיבה רגיל שניתן לבדוק.קריאה לאחר
shutdown($sock, 0)מחזירה end-of-file מיד, לא שגיאה. כל נתון שכבר היה בתור ב־buffer הקבלה של הקרנל מושלך.לא סוקט: קריאה ל־
shutdownעל מטפל קובץ רגיל קובעת את$!ל־ENOTSOCKומחזירה0.לא מחובר:
shutdownעל סוקט שמעולם לא חובר (תוצאה רעננה שלsocket, או סוקט מאזין) קובע את$!ל־ENOTCONNומחזיר0.shutdown כפול: סגירת אותו חצי פעמיים בדרך כלל מחזירה
0עםENOTCONN. קוד נייד מתעלם מהכישלון השני במקום להתייחס אליו כקריטי.מטפל קובץ סגור: מחזיר
undef; תחתuse warningsנפלטת אזהרתshutdown() on closed socket.ה־descriptor אינו סגור:
shutdownמנטרל את הכיוונים שביקשת אך משאיר את ה־file descriptor פתוח. יש לקרוא ל־close(או לתת למטפל לצאת מתחום) כשמסיימים איתו ממש.descriptors משותפים בין
fork: זה המקרה ש־shutdownתוכנן עבורו. כל התהליכים המחזיקים את ה־descriptor רואים את ה־shutdown נכנס לתוקף מיד; אין להם תצוגות נפרדות.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
close- לשחרר את ה־descriptor בתהליך זה; אינו משפיע על עותקים שנעשה להם fork ואינו מסמן end-of-file לעמית עד שהעותק האחרון נסגרsocket- ליצור את הסוקט ש־shutdownפועל עליוconnect- לבסס את החיבור;shutdownעל סוקט לא־מחובר נכשל עםENOTCONNaccept- מייצר את הסוקט המחובר בצד השרת שעובר בדרך כלל חצי־סגירה עםshutdownSocket- מייצא אתSHUT_RD,SHUT_WR,SHUT_RDWRואת שאר הקבועים ברמת הסוקט$!- מחרוזת שגיאת מערכת לבדיקה לאחר החזרת0