Presentation is loading. Please wait.

Presentation is loading. Please wait.

מנגנון תקשורת ב-Linux סכמת שרת לקוח: client/server

Similar presentations


Presentation on theme: "מנגנון תקשורת ב-Linux סכמת שרת לקוח: client/server"— Presentation transcript:

1 מנגנון תקשורת ב-Linux סכמת שרת לקוח: client/server
תקשורת ב-Linux ו-Unix מנגנון תקשורת ב-Linux סכמת שרת לקוח: client/server

2 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
מודל השכבות רשת תקשורת: חיבורים המאפשרים תקשורת בין מחשבים פרוטוקולי תקשורת מאפשרים העברת נתונים ברשת פועלים בשכבות שונות, כשלכל שכבה תפקיד משלה. אוסף פרוטוקולי התקשורת הנפוץ ביותר נקרא TCP/IP מכיל 4 שכבות אפליקציות המשתמשות ברשת Application (telnet, ftp …) תקשורת בין תהליכים (ולא מחשבים) Transport (TCP, UDP) ניתוב חבילות בין תחנות (לא שכנות) Internet (IP) העברת חבילה בין תחנות שכנות Data Link (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

3 Networking API של Linux
נתמקד בתמיכה של Linux בפרוטוקולי TCP/IP: קריאות מערכת המאפשרות יצירת תקשורת עם תהליכים מרוחקים. מבני נתונים המשמשים את קריאות המערכת הנ"ל כל קריאות המערכת שנראה משתמשות ב-sockets. תחילה נגדיר את ה-socket, ואח"כ נחבר אותו לפורט המתאים עבור כל הקריאות צריך להוסיף : #include <sys/types.h> #include <sys/socket.h> (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

4 הממשק: יצירת socket חדש
int socket(int family, int type, int protocol) פרמטרים: family ארכיטקטורת הרשת לביצוע התקשורת (AF_INET) type מודל התקשורת ברשת. SOCK_STREAM עבור תקשורת connection oriented , מבוססת stream ואמינה (ממומשת ע"י TCP) protocol מגדיר את פרוטוקול התקשורת של שכבת ה Transport. פרמטר 0 בוחר את פרוטוקול ברירת המחדל (TCP עבור SOCK_STREAM) ערך חזרה: במקרה של הצלחה, מחזיר descriptor המצביע ל-socket החדש שייך ל-PDT של התהליך כמו descriptors אחרים המצביעים על קבצים פתוחים, pipes, ... (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

5 הממשק: קישור של socket לפורט
int bind(int sockfd, struct sockaddr * my_addr, int addrlen) פרמטרים: sockfd ה-descriptor של ה-socket אותו מחברים. my_addr כתובת אליה מקשרים. הכתובת מכילה את כתובת ה-IP של המחשב המקומי ואת מספר ה-port אליו יקושר ה-socket addrlen אורך של my_addr בבתים. ערך חזרה: 0 במקרה של הצלחה, 1 במקרה של כישלון. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

6 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: האזנה הצהרת כוונה לקבל בקשות תקשורת והגדרת אורך תור מקסימלי של בקשות ממתינות. int listen(int sockfd, int num) פרמטרים: sockfd מזהה של ה-socket num מספר מקסימלי של בקשות התחברות ממתינות ערך חזרה: 0 במקרה של הצלחה, 1 במקרה של כישלון. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

7 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: קבלת בקשות מחכה על ה-socket הנתון לבקשות תקשורת. אם יש בקשות הממתינות בתור: מוציא בקשה מהתור יוצר socket חדש ומקצה לו descriptor חדש. int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) פרמטרים: sockfd ה-descriptor של ה-socket עליו מחכים לבקשות תקשורת Addr כתובת שולח בקשת תקשורת שהתקבלה, מוצב בתוך הקריאה. addrlen אורך הכתובת בבתים. ערך חזרה: במקרה של הצלחה ה-descriptor של ה-socket החדש שנוצר, אחרת 1-. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

8 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: התחברות מנסה ליצור תקשורת עם תהליך שמקשיב על הכתובת serv_addr (מורכבת מכתובת IP ומספר port) int connect(int sockfd, const struct sockaddr* serv_addr, socklen_t addrlen) פרמטרים: sockfd ה-descriptor של socket serv_addrהכתובת עליה מקשיב התהליך איתו מנסים להתקשר addrlen אורך הכתובת בבתים. ערך חזרה: 0 במקרה של הצלחה, 1 במקרה של כישלון. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

9 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: כתיבה ל socket אפשר לכתוב ל-socket באמצעות קריאת write, כמו לקבצים. ה-descriptor שמועבר הוא descriptor של ה-socket השולח, וההודעה תועבר ל-socket אליו מקשיב התהליך השני. פעולה מיוחדת, עם דגלים לאפשרויות שליחה מיוחדות int send(int sockfd,const void *msg, size_t len, int flags) ערך חזרה: במקרה של הצלחה, מספר הבתים שנשלחו, אחרת 1-. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

10 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: קריאה מה socket ניתן לקרוא מה-socket באמצעות קריאת read, כמו לקבצים. ה-descriptor שמועבר הוא descriptor של ה-socket הקורא, שחייב להיות מחובר (connected) ל- socket אחר. פעולה מיוחדת, עם דגלים לאפשרויות קריאה מיוחדות int recv(int sockfd, void *buf, size_t len, int flags) ערך חזרה: במקרה של הצלחה, מספר הבתים שנקראו, אחרת 1-. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

11 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
הממשק: סגירת socket סגירת התקשורת עם המחשב המרוחק ושחרור ה-descriptor שהצביע על ה-socket. int close (int sockfd) פרמטר: sockfd ה-descriptor של ה- socket לסגירה. ערך חזרה: 0 במקרה של הצלחה, 1 במקרה של כישלון. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

12 סכמת שרת לקוח: client/server
תהליך אחד, הלקוח, מבקש שירות מתהליך אחר, השרת. למשל, שרתי telnet, web, ftp. השרת מטפל בבקשות של מספר לקוחות בו זמנית. לדוגמה, שרת telnet "מקשיב" על פורט 23 לבקשות התחברות מלקוחות (שזהותם לא ידועה מראש) כשמתקבלת בקשת התחברות נוצר telnet session בין השרת ללקוח שהתחבר. נשתמש ב-sockets: מאפשרים לאפליקציה להבדיל בין telnet sessions שונים. לכל session מתאים זוג sockets בשרת ובלקוח. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

13 יצירת connection באופן לא סימטרי
השרת יוצר socket מחבר אותו לפורט עליו הוא מקשיב מחכה על ה socket לבקשות תקשורת נכנסות הלקוח יוצר socket מנסה להתחבר אל כתובת IP ופורט של השרת כאשר connection מוקם, התקשורת היא סימטרית: שני הצדדים יכולים לשלוח הודעות אחד לשני דרך ה socket כל TCP session שנוצר כך מוגדר באופן חד ערכי ע"י רביעיה (source IP, source Port, destination IP, destination Port) (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

14 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
מימוש של שרת-לקוח עם sockets Client side: sd=socket() connect(sd, dst) write(sd, …) read(sd, …) close(sd) Server side: sd=socket() bind(sd, port) listen(sd,…) new_sd=accept(sd) write(new_sd, …) read(new_sd, …) close(new_sd) (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

15 מימוש שרת-לקוח עם sockets: הסברים
השרת חייב לקרוא ל bind() כדי לחבר את ה sdשלו ל port מסוים (אחרת הוא יחכה לבקשות על port אקראי) בדרך כלל כמה לקוחות שולחים בקשות לתקשורת עם השרת. בקשות אלה נשמרות ע"י הkernel בתוך תור. כאמור listen מגדירה את אורך התור. השרת מקבל כל פעם בקשה אחת ע"י accept() כאשר הטיפול בבקשה הוא ארוך, כדאי אחרי accept() לעשות fork() ולתת לבן לטפל בבקשה ולאב לקבל את הבקשות האחרות. אפשרות נוספת היא טיפול בבקשות ע"י חוטים חדשים (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

16 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
מציאת כתובת מציאת כתובת IP של מחשב ברשת לפי שם המחשב (hostname). struct hostent * gethostbyname(const char *hostname); פרמטרים: hostname – שם המחשב ערך חזרה: struct hostent * - מצביע למבנה נתונים המתאר את המחשב המבוקש. דוגמא: struct hostent *h = gethostbyname(“t2.technion.ac.il”) h->h_addr יכיל את כתובת ה IP של t2 h->h_lenght אורך ה h->h_addr h->h_name יכיל את המחרוזת t2.technion.ac.il (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

17 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
החלפת Endians במעבדים שונים, יש סדר שונה בין LSB (least significant byte) ו MSB (most significant byte). כדי שנוכל להעביר אינפורמציה בין מחשבים שונים ברשת, צריכים להעביר את המספרים (int, short, long) ליצוג אחיד. בזה מטפלות 4 הפונקציות הבאות: u_long htonl(u_long); // host to network long (32 bits) u_short htons(u_short); // host to network short (16 bits) u_long ntohl(u_long); // network to host long (32 bits) u_short ntohs(u_short); // network to host short (16 bits) הסבר לציור: הביטוי endian בא ממסעות גוליבר (של יונתן סוויפט) שהוא פוגש שני שבטי גמדים שנלחמים כי אין הסכמה מאיזה צד לאכול את הביצה הרכה (הרחב או הצר). זה ציור מהספר. (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

18 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
מבני נתונים לכתובות struct sockaddr_in { short int sin_family; //Address family, AF_xxx unsigned short int sin_port; // Port number struct in_addr sin_addr; // Internet address unsigned char sin_zero[8]; // for allignments }; struct sockaddr { unsigned short sa_family; // address family, AF_xxx char sa_data[14]; // 14 bytes of protocol address struct in_addr { unsigned long s_addr; //32-bit long,(4 bytes) IP address } (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

19 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
קוד שרת 1 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> void error(char *msg) { perror(msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; if (argc < 2) { fprintf(stderr,"ERROR, no port provided\n"); (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

20 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
קוד שרת 2 sockfd = socket(AF_INET,SOCK_STREAM,0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); listen(sockfd,5); clilen = sizeof(cli_addr); (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

21 קוד שרת 3 האם הקוד הנ"ל תמיד יעבוד נכון?
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); bzero(buffer,256); n = read(newsockfd, buffer, 255); if (n < 0) error("ERROR reading from socket"); printf("Here is the message: %s\n",buffer); n = write(newsockfd,"I got your message",18); error("ERROR writing to socket"); close(newsockfd); close(sockfd); //or goto accept to wait for another clients return 0; האם הקוד הנ"ל תמיד יעבוד נכון? (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

22 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
קוד לקוח 1 #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sockfd, portno, n; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256]; (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

23 תרגול 11 – ניהול זיכרון ב-Linux: סקירה
קוד לקוח 2 if (argc < 3) { fprintf(stderr,"usage %s hostname port\n", argv[0]); exit(0); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); portno = atoi(argv[2]); server = gethostbyname(argv[1]); if (server == NULL) { fprintf(stderr,"ERROR, no such host\n"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה

24 קוד לקוח 3 האם הקוד הנ"ל תמיד יעבוד נכון?
bcopy((char *)server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0)( error("ERROR connecting"); n = write(sockfd, ”HELLO THERE”, sizeof(“HELLO THERE”)); if (n < 0) error("ERROR writing to socket"); bzero(buffer,256); n = read(sockfd,buffer,255); error("ERROR reading from socket"); printf("%s\n",buffer); close(sockfd); return 0; } האם הקוד הנ"ל תמיד יעבוד נכון? (c) ארז חדד 2003 תרגול 11 – ניהול זיכרון ב-Linux: סקירה


Download ppt "מנגנון תקשורת ב-Linux סכמת שרת לקוח: client/server"

Similar presentations


Ads by Google