11.2 שרת TCP מתקדם תרגול
תרגול - שרת TCP מתקדם - advanced TCP server¶
תרגול 1 - שרת הד עם fork¶
- כתבו שרת TCP שמשתמש ב-fork כדי לטפל בכמה לקוחות במקביל.
- השרת מקבל חיבור, עושה
fork, והילד מטפל בלקוח (echo - שולח בחזרה מה שקיבל). - תהליך האב מדפיס את ה-PID של כל ילד שנוצר.
- טפלו ב-SIGCHLD כדי למנוע תהליכי zombie.
- בדקו שאתם יכולים לחבר כמה לקוחות (עם
nc) במקביל.
רמז: אל תשכחו שהאב צריך לסגור את client_fd והילד צריך לסגור את server_fd.
תרגול 2 - שרת צ'אט עם threads¶
- כתבו שרת TCP שמשתמש ב-threads. השרת מנהל רשימה גלובלית של כל הלקוחות המחוברים.
- כשלקוח שולח הודעה, השרת שולח אותה לכל שאר הלקוחות (broadcast).
- השתמשו ב-mutex כדי להגן על הרשימה הגלובלית מגישה מקבילית.
- כשלקוח מתנתק, הסירו אותו מהרשימה.
מבנה מוצע:
#define MAX_CLIENTS 100
int client_fds[MAX_CLIENTS];
int client_count = 0;
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
רמז: כשעושים broadcast, צריך לנעול את המוטקס, לעבור על כל הלקוחות ולשלוח, ואז לשחרר. שימו לב לא לשלוח ללקוח שמאיר - הוא שלח את ההודעה.
תרגול 3 - שרת הד עם select¶
- כתבו שרת TCP שמשתמש ב-
selectכדי לטפל בכמה לקוחות ב-thread אחד. - השרת מנטר גם את סוקט השרת (לחיבורים חדשים) וגם את כל סוקטי הלקוחות (לנתונים).
- כשלקוח שולח נתונים, השרת שולח אותם בחזרה עם הprefix
[fd N](כש-N הוא מספר הfd). - הדפיסו הודעה כשלקוח מתחבר ומתנתק.
רמז: זכרו ש-select משנה את ה-fd_set. צריך לבנות אותה מחדש בכל סיבוב של הלולאה.
תרגול 4 - שרת הד עם epoll¶
- כתבו שרת TCP שמשתמש ב-
epollכדי לטפל בכמה לקוחות. - השרת מבצע echo בדיוק כמו בתרגול הקודם, אבל עם epoll במקום select.
- הוסיפו ספירה של כמה בתים כל לקוח שלח. כשלקוח מתנתק, הדפיסו את הסטטיסטיקה שלו.
לצורך שמירת הסטטיסטיקה, תצטרכו מבנה נתונים שמקשר fd למידע על הלקוח:
רמז: אפשר להשתמש ב-
event.data.ptrבמקוםevent.data.fdכדי לשמור מצביע ל-struct client_data. ככה כשepoll מחזיר אירוע, יש לכם גישה ישירה לכל המידע על הלקוח.
תרגול 5 - השוואת ביצועים¶
- קחו את שלושת השרתים שכתבתם (fork, select, epoll) ובדקו את הביצועים שלהם.
- כתבו תוכנית בדיקה (benchmark client) שפותחת N חיבורים במקביל ושולחת M הודעות בכל חיבור.
- מדדו את הזמן הכולל עם
clock_gettime(CLOCK_MONOTONIC, ...). - הריצו את הבדיקה עם N=10, N=100, N=500 ותעדו את התוצאות.
מבנה מוצע לתוכנית הבדיקה:
/* עבור כל חיבור, צרו thread שמתחבר לשרת ושולח הודעות */
void *benchmark_thread(void *arg) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* connect... */
for (int i = 0; i < messages_per_client; i++) {
write(sockfd, msg, msg_len);
read(sockfd, buffer, sizeof(buffer));
}
close(sockfd);
return NULL;
}
רמז: השתמשו ב-
pthread_createליצירת threads של הלקוחות ו-pthread_joinלחכות שכולם יסיימו.