setsockopt#
מגדיר אפשרות ברמת הקרנל על סוקט פתוח.
setsockopt הוא העטיפה של Perl סביב קריאת המערכת setsockopt(2) של POSIX. הוא כותב את האפשרות הקרויה ב־OPTNAME ברמת הפרוטוקול LEVEL על מטפל הקובץ של ה־SOCKET שכבר נפתח, באמצעות הערך הארוז ב־OPTVAL. זהו הכפתור לכל מה שהקרנל מאפשר לכם לכוון על סוקט - שימוש חוזר בכתובות, keepalives, timeouts, האלגוריתם של Nagle, חברות multicast, גודלי buffer לשליחה וקבלה, התנהגות SO_LINGER ב־close, וכן הלאה. שמות סימבוליים ל־LEVEL ול־OPTNAME באים מהמודול Socket.
תקציר#
setsockopt SOCKET, LEVEL, OPTNAME, OPTVAL
מה מקבלים בחזרה#
ערך אמת בהצלחה, undef בכשל (עם $! קבוע ל־errno הבסיסי: EBADF, ENOPROTOOPT, EINVAL, ENOTSOCK, וכו«). תמיד בדקו את ערך ההחזרה - אפשרות שנתעלמה ממנה בשקט אומרת שהתוכנית רצה עם ברירות מחדל שונות ממה שהקוד קורא:
setsockopt($sock, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
or die "setsockopt SO_REUSEADDR: $!";
מצב גלובלי שהוא נוגע בו#
אין ישירות. setsockopt קובע את $! בכשל; זה הגלובל היחיד של המפענח המעורב. ההשפעה היא על מצב הסוקט בצד הקרנל, לא על משתנה כלשהו ברמת Perl.
OPTVAL - בתים ארוזים או מספר שלם חשוף#
רוב אפשרויות הסוקט לוקחות דגל int של C. setsockopt מקבל כל אחת מהצורות לנוחות:
מחרוזת בתים ארוזה שתבניתה תואמת לסוג ה־C של האפשרות, בנויה בדרך כלל עם
pack:pack("l", 1)לבוליאני,pack("ll", $on_secs, $on_usecs)ל־struct timeval,pack("ii", $on, $linger)ל־struct linger.מספר שלם פשוט, שהוא קיצור ל־
pack("i", OPTVAL). שימושי עבורSO_REUSEADDR,TCP_NODELAY, ודגלים בוליאניים אחרים:setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, 1);
אפשרויות שערכן הוא struct (SO_LINGER, SO_RCVTIMEO, IP_ADD_MEMBERSHIP) חייבות להיות מועברות כמחרוזת pack מפורשת. מספר שלם חשוף שם מפיק EINVAL או, גרוע יותר, כותב בשקט זיכרון בגודל שגוי שהקרנל מפרש לא נכון.
דוגמאות#
השבתת האלגוריתם של Nagle על סוקט TCP כך שכתיבות קטנות יוצאות מיד - שימושי לפרוטוקולים רגישי השהיה (shells אינטראקטיביים, תעבורת משחקים, RPC):
use Socket qw(IPPROTO_TCP TCP_NODELAY);
setsockopt($sock, IPPROTO_TCP, TCP_NODELAY, 1)
or die "TCP_NODELAY: $!";
מתן רשות לשרת לקשור מחדש פורט שעדיין ב־TIME_WAIT מתהליך קודם - קריאת setsockopt הנפוצה ביותר בפועל, והיא חייבת לבוא לפני bind:
use Socket qw(SOL_SOCKET SO_REUSEADDR);
setsockopt($srv, SOL_SOCKET, SO_REUSEADDR, pack("l", 1))
or die "SO_REUSEADDR: $!";
bind($srv, sockaddr_in(9000, INADDR_ANY))
or die "bind: $!";
הגדרת timeout לקבלה כך ש־recv חוסם או קריאה מהסוקט מחזירים עם EAGAIN / EWOULDBLOCK לאחר 5 שניות במקום להיתקע לנצח. ערך האפשרות הוא struct timeval ארוז:
use Socket qw(SOL_SOCKET SO_RCVTIMEO);
my $tv = pack("l!l!", 5, 0); # 5 seconds, 0 microseconds
setsockopt($sock, SOL_SOCKET, SO_RCVTIMEO, $tv)
or die "SO_RCVTIMEO: $!";
הפעלת בדיקות keepalive של TCP כך שחיבורים חצי־פתוחים (העמית קרס, הכבל נמשך) בסופו של דבר מבחינים בהם והסוקט נכשל במקום להיחסם ללא הגבלה:
use Socket qw(SOL_SOCKET SO_KEEPALIVE);
setsockopt($sock, SOL_SOCKET, SO_KEEPALIVE, 1)
or die "SO_KEEPALIVE: $!";
לגרום ל־close להיחסם עד 10 שניות בעוד הקרנל מבצע flush של נתונים שלא נשלחו, ואז להשליך ולאפס. SO_LINGER לוקח struct של שני מספרים שלמים: דגל ה־on וה־timeout בשניות:
use Socket qw(SOL_SOCKET SO_LINGER);
setsockopt($sock, SOL_SOCKET, SO_LINGER, pack("ii", 1, 10))
or die "SO_LINGER: $!";
הגדלת buffer הקבלה של הקרנל לסוקט להעברת bulk. הקרנל בדרך כלל מכפיל את הערך שאתם מבקשים ומגביל אותו ב־net.core.rmem_max:
use Socket qw(SOL_SOCKET SO_RCVBUF);
setsockopt($sock, SOL_SOCKET, SO_RCVBUF, 1 << 20) # 1 MiB
or die "SO_RCVBUF: $!";
מקרי קצה#
SOCKETחייב להיות כבר פתוח.setsockoptאינו יוצר את הסוקט - קראו תחילה ל־socket. מטפל קובץ סגור או שמעולם לא נפתח נכשל עםEBADF.הסדר משנה.
SO_REUSEADDRחייב להיות מוגדר לפניbind.SO_KEEPALIVEיכול ללכת לפני או אחריconnect, אך עבור סוקטי שרת הגדירו אותו על מטפל הקובץ של הילד המקובל המוחזר על־ידיaccept, לא על המאזין - אפשרויות לא תמיד מתפשטות.קיצור מספר שלם הוא
pack("i", N), לאpack("l", N). בפלטפורמות שבהןintו־longשונים בגודלם, העברת מספר שלם פשוט והעברתpack("l", N)כותבים ספירות בתים שונות. שניהם במקרה עובדים עבור אפשרויות בוליאניות בגודל־intהנפוצות ב־LP64 Linux, אך צורת הקיצור היא ברירת המחדל הניידת.אפשרויות עם ערך struct זקוקות ל־
packמפורש.SO_LINGER,SO_RCVTIMEO,SO_SNDTIMEO,IP_ADD_MEMBERSHIP,IP_MREQ, ודומיהם לוקחים structs בתבנית קבועה. העבירו מחרוזת ארוזה באורך הנכון או שהקרנל ידחה את הקריאה עםEINVAL.LEVELבוחר את מרחב השמות של האפשרות.SOL_SOCKETלאפשרויות גנריות,IPPROTO_TCPלאפשרויות ייחודיות־TCP (TCP_NODELAY,TCP_KEEPIDLE),IPPROTO_IPל־IPv4 (IP_TTL,IP_ADD_MEMBERSHIP),IPPROTO_IPV6ל־IPv6. אי־התאמה ביןLEVELל־OPTNAMEנותנתENOPROTOOPT.אפשרויות לקריאה־בלבד או שאינן נתמכות נכשלות עם
ENOPROTOOPT. זה גם יורה כאשר הקרנל פשוט אינו מכיר את האפשרות - שכיח בהעתקת קוד בין מערכות הפעלה.אפשרויות מורשות. כמה אפשרויות (
SO_PRIORITYמעל ערכים מסוימים,IP_TRANSPARENT,SO_BINDTODEVICE) דורשותCAP_NET_ADMINב־Linux; קריאה לא־מורשית נכשלת עםEPERM.קריאה חזרה היא
getsockopt, לאsetsockopt. ל־setsockoptאין צורת שאילתה; השתמשו ב־getsockoptכדי לוודא מה הקרנל אכן אחסן (הוא עשוי לעגל, להגביל, או להכפיל את הערך).
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
getsockopt- המקבילה לשאילתה; קראו חזרה אפשרות כדי לראות מה הקרנל אכן יישםsocket- יוצר את מטפל הקובץ של הסוקט ש־setsockoptמגדיר; חייב להיקרא תחילהbind- הגדירוSO_REUSEADDRעםsetsockoptלפני קריאה ל־bindעל סוקט שרתaccept- אפשרויות שמוגדרות על המאזין לא כולן מתפשטות; יישמו מחדש אפשרויות לכל־חיבור על המטפל המקובלpack- בונה את מחרוזת הבתים שלOPTVALעבור אפשרויות עם ערך struct כמוSO_LINGERו־SO_RCVTIMEOSocket- מקורSOL_SOCKET,IPPROTO_TCP,SO_REUSEADDR,TCP_NODELAYושאר הקבועים הסימבוליים