getservbyname#
חיפוש שירות רשת לפי שמו הטקסטואלי והפרוטוקול שלו.
getservbyname מתייעצת במסד נתוני השירותים של המערכת (בדרך כלל /etc/services, או לכל מקור שאליו nsswitch.conf מנתב את המקור services) ומחזירה את הרשומה ששמה או הכינוי שלה תואם ל־NAME תחת פרוטוקול ההעברה המכונה PROTO. זוהי עטיפת Perl סביב קריאת getservbyname(3) של ספריית ה־C, והיא הדרך להפוך את "https" ל־443 בלי לקודד את המספר באופן קשיח.
שני הארגומנטים הם מחרוזות. NAME הוא שם השירות או הכינוי ("http", "ssh", "imaps"); PROTO הוא שם הפרוטוקול ("tcp", "udp", "sctp") - לא מספר, ולא קבוע מסגנון SOCK_STREAM.
תקציר#
my $port = getservbyname NAME, PROTO; # scalar
my ($name, $aliases, $port, $proto) = getservbyname NAME, PROTO; # list
מה מקבלים בחזרה#
בהקשר סקלר, מספר הפורט כמספר שלם פשוט בסדר בתי המארח - מוכן להזנה ל־pack עם "n" או לבנאי sockaddr_in. אם לא נמצאה רשומה תואמת, ההחזרה היא undef.
בהקשר רשימה, ארבעת השדות של רשומת ה־servent:
$name- שם השירות הקנוני (השם הראשי, לא הכינוי לפיו חיפשנו).$aliases- מחרוזת של שמות חלופיים מופרדים ברווחים.$port- מספר פורט, סדר בתי המארח.$proto- שם הפרוטוקול הקנוני כפי שמוחזר על־ידי המפענח, בדרך כלל שווה ל־PROTOשהועבר.
אם לא נמצאה רשומה תואמת בהקשר רשימה, ההחזרה היא הרשימה הריקה.
הפורט הוא בסדר בתי מארח. ממשקי רשת מצפים לסדר בתי רשת, לכן יש להעבירו דרך pack עם התבנית "n" - או לתת ל־Socket לעשות זאת באמצעות sockaddr_in.
מצב גלובלי שהוא נוגע בו#
מחזיק מטפל פתוח למסד נתוני השירותים בין קריאות כאשר מסד הנתונים נפתח עם
setserventבאמצעות STAYOPEN שאינו אפס.endserventסוגרת אותו.מגדיר את
$!בכישלונות חיפוש שנובעים משגיאת מערכת (קובץ מסד הנתונים חסר, backend של NSS לא נגיש). מקרה פשוט של ״אין שירות כזה״ מדווח על־ידי החזרתundef/ הרשימה הריקה, ולא על־ידי הגדרת$!.
דוגמאות#
פענוח שירות מוכר לפורט שלו:
my $port = getservbyname("https", "tcp");
print $port, "\n"; # 443
רשומה מלאה בהקשר רשימה:
my ($name, $aliases, $port, $proto) = getservbyname("http", "tcp");
print "$name ($aliases) -> $port/$proto\n";
# www (www-http http) -> 80/tcp
# (exact aliases depend on /etc/services)
בניית sockaddr_in עבור connect, המרת הפורט מסדר מארח לסדר רשת באמצעות pack:
use Socket;
my $port = getservbyname("smtp", "tcp")
or die "smtp/tcp not in services db";
my $addr = sockaddr_in($port, inet_aton("mail.example.com"));
socket(my $s, AF_INET, SOCK_STREAM, getprotobyname("tcp")) or die $!;
connect($s, $addr) or die "connect: $!";
הבחנה בין ״לא נמצא״ ל־״פרוטוקול שגוי״ - שירות הקיים תחת tcp אך לא תחת udp מחזיר undef כאשר הפרוטוקול אינו תואם:
defined(getservbyname("https", "tcp")) or die "expected 443";
defined(getservbyname("https", "udp")) or warn "no https/udp entry";
חיפוש לפי כינוי - כינויים מתפענחים זהה לשם הקנוני, אך ה־$name המוחזר תמיד הקנוני:
my ($name) = getservbyname("www", "tcp");
print $name, "\n"; # "http" on most systems
מקרי קצה#
שירות לא־ידוע: מחזיר
undefבהקשר סקלר, רשימה ריקה בהקשר רשימה.$!לא נקבע עבור החטאה פשוטה - רק עבור שגיאות מערכת תשתיתיות.פרוטוקול לא־ידוע: זהה לשירות לא־ידוע.
getservbyname("ssh", "xyzzy")לא מחזיר דבר; לא מועלית שגיאה נפרדת.רגישות לאותיות גדולות וקטנות: שמות שירותים ופרוטוקולים נשווים ללא רגישות לאותיות גדולות וקטנות על־ידי המפענח של המערכת בכל פלטפורמה שאנו תומכים בה;
"HTTPS"ו־"https"נותנים אותה תשובה.הפורט הוא בסדר בתי מארח: העברתו ישירות לפורמט חוט היא באג. יש להשתמש ב־
pack("n", $port)או ב־sockaddr_in($port, $addr)- שניהם מטפלים בהמרה.NAMEו־PROTOשניהם נדרשים. אין צורה של ארגומנט יחיד; השמטתPROTOהיא שגיאת זמן הידור.מלכודת קדימות: כמו כל דמוי־אונרי־מבוסס־שם במשפחה זו,
getservbynameהוא אופרטור רשימה. יש להוסיף סוגריים בעת שילוב עם אופרטורים:getservbyname "http", "tcp" == 80 # WRONG: parses as # getservbyname("http", ("tcp" == 80)) getservbyname("http", "tcp") == 80 # right
Threads: על מערכות עם
getservbyname_r(3), Perl משתמשת בווריאנט הריאנטרנטי באופן שקוף. על אותן מעט פלטפורמות שחסרות אותו, חיפושים מקבילים ממספר threads עלולים לדרוס זה את תוצאותיו של זה.ממשק לפי־שם:
Net::servent(ליבה) עוטף קריאה זו ומחזיר עצם עם accessors בעלי שם, במחיר הקצאה אחת לכל חיפוש.
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
getservbyport- חיפוש הפוך: פורט + פרוטוקול → רשומת שירותgetservent- לעבור על כל רשומה במסד נתוני השירותים, רשומה אחת בכל פעםsetservent- להחזיר לאחור (או לפתוח בקביעות) את מסד נתוני השירותים לפני סריקהendservent- לסגור את מסד נתוני השירותים שנפתח על־ידיsetserventgetprotobyname- חיפוש משלים עבור הארגומנטPROTOכאשר נדרש גם מספר הפרוטוקול המספרי שלוSocket-sockaddr_inו־pack_sockaddr_inצורכים את הפורט בסדר־מארח המוחזר כאן