PracticU

Client-Server Architecture - חלק 2

בלי כתוביותעם כתוביות
PracticU › קורס תכנות מתקדם - #Advanced .NET C › Client-Server Architecture - חלק 2
מילון מושגים:
DLL - קובץ ספרייה ב-Windows המכיל קוד ופונקציות שתוכנות שונות יכולות לטעון ולהשתמש בהן במשותף.
טופס - אזור בממשק שבו המשתמש מזין נתונים בשדות ושולח אותם, למשל טופס הרשמה או התחברות.
אירוע - התרחשות שהמערכת מזהה ויכולה להגיב לה, כמו לחיצת עכבר, הקשה או סיום פעולה.
לולאה - מבנה בקרה שחוזר על קטע קוד שוב ושוב כל עוד תנאי מתקיים או עבור כל פריט באוסף.
תהליכון - יחידת ביצוע בתוך תהליך, המאפשרת להריץ כמה מהלכים במקביל ולחלוק את אותו זיכרון.
חריגה - מצב שגיאה שמתרחש בזמן ריצת התוכנית ומפסיק את המהלך הרגיל, אלא אם הקוד תופס ומטפל בו.
GUID - מזהה ייחודי גלובלי: מספר ארוך שנוצר כך שהסיכוי לכפילות שלו זניח, ומשמש לזיהוי אובייקטים.
תמונה - קובץ גרפי המוצג על המסך. בהקשר של וירטואליזציה או Docker, תבנית מוכנה שממנה יוצרים מכונה או קונטיינר.

Client-Server Architecture - חלק 2
בשיעור הזה בונים את הלקוח והשרת כאפליקציות Windows Forms עם תקשורת דרך ה-DLL המשותף, ומטפלים בבעיית העדכון של ה-UI מתרד אחר ובסגירת החיבורים.
השלבים העיקריים
1. טופס הלקוח: טופס עם תיבת טקסט, לחצן Send, ListBox להודעות ותפריט עם Connect ו-Disconnect. הטופס נפתח במרכז המסך, בלי אפשרות הגדלה, והתיבה בקבוצה (GroupBox) שמופעלת רק אחרי התחברות.
2. יצירת Communicator בחיבור: בלחיצה על Connect הלקוח יוצר TcpClient, מתחבר לשרת, ומעביר את הסוקט ל-Communicator. בלחיצה על Disconnect נסגרים ה-Communicator והחיבור, והממשק חוזר למצב קודם.
3. אירוע קבלת הודעה: הלקוח נרשם לאירוע GotMessage של ה-Communicator, ומוסיף כל הודעה שמתקבלת לראש הרשימה בעזרת Insert. התוספת בראש הרשימה מאפשרת לראות תמיד את ההודעה האחרונה.
4. טופס השרת: טופס דומה לזה של הלקוח, בצבע רקע שונה כדי להבדיל בינם. השרת מפעיל TcpListener על פורט מוגדר, ומתחיל תרד שמקבל לקוחות חדשים בלולאה.
5. קבלת לקוחות בתרד: ב-AcceptSocket חוסם עד שמתחבר לקוח, ואז נוצר Communicator חדש, נרשמים לאירוע שלו, והוא מתווסף לאוסף כל הקומוניקטורים.
6. שידור לכל הלקוחות: כשמתקבלת הודעה מלקוח, השרת עובר על כל הקומוניקטורים ושולח אליהם את ההודעה. לקוח שנכשל בשליחה מוסר מהאוסף. מוסיפים את הלקוחות מהסוף להתחלה, כדי שהסרה לא תשבש את הלולאה.
7. שגיאת Cross-Thread: האירוע מגיע מתרד אחר, ולכן אסור לגעת ב-ListBox ישירות. פותרים זאת עם Invoke, שמפעיל את הקוד בתרד של הטופס, בעזרת ביטוי למדה.
8. סגירה נכונה: בזמן סגירה מבטלים את דגל ההאזנה, סוגרים את הסטרים והסוקט, ומטפלים בחריגות SerializationException, IOException ו-SocketException. בלי הטיפול הזה, החריגה שמופיעה כשההאזנה החסומה נסגרת באמצע הריצה עוצרת את התוכנית.
9. בדיקה עם כמה לקוחות: שרת אחד ושלושה לקוחות מתקשרים זה עם זה, וההודעה מגיעה לכולם כולל השולח. בדיקה עם F5 בלי דיבוג מראה שהבעיה של Cross-Thread נפתרה.
10. הרחבה: בשיעור מציינים שחיבור שמתנתק צריך להודיע על כך לשרת כדי שיוסר מהאוסף, ושזה נשאר כתרגיל.
בסיום השיעור ברור שארכיטקטורת לקוח-שרת בנויה מרכיב תקשורת משותף, מנהל בשרת שמחזיק את כל הלקוחות, ואירועים שמעבירים מידע בין הרכיבים בלי שיכירו זה את זה.
תרגילים
התרגילים כוללים צ'אט עם אובייקט Message שמכיל כינוי, טקסט וצבע, שמירה של ההודעות בקובץ נפרד לכל לקוח, שליחת תמונות מהלקוח לשרת עם שם ייחודי שנוצר על ידי GUID, ושליחה של תמונה רנדומלית מהשרת חזרה ללקוח.
השיעור הבא בקורס: תרגילים על Client-Server Architecture ב-#C

פרקי ההרצאה: Client-Server Architecture - חלק 2

  1. 00:00

    בניית ה-Client ב-WinForms

  2. 01:37

    עיצוב טופס הלקוח ותיבת הודעה

  3. 04:00

    הצגת הודעות ב-List Box

  4. 05:02

    תפריט Connect ו-Disconnect

  5. 08:06

    חיבור עם Communicator library

  6. 11:48

    טיפול באירוע GotMessage

  7. 16:31

    הוספת פרויקט ה-Server

  8. 19:57

    האזנה ללקוחות עם TcpListener

תמלול ההרצאה: Client-Server Architecture - חלק 2

הטקסט המלא של הדקות הראשונות בהרצאה «Client-Server Architecture - חלק 2» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.

  1. 00:02

    והדבר הראשון שאנחנו הולכים לבנות זה את הקליינט כי הקליינט יותר פשוט לבנייה מהסרבר כאן אנחנו הולכים ומוסיפים new project ובואו נבחר winform application כאן אנחנו רוצים לבנות פרויקט או טופס בוא נגיד קודם כל פרויקט כמובן שהפרויקט הזה מהווה את הקליינט זה יהיה הקליינט

  2. 00:33

    שלנו נבצע אוקיי יש לנו פה טופס אחד אנחנו רוצים לקרוא לטופס הזה קליינט פורם מפני שהוא טופס יש לנו פה את קליינט פורם כן תשנה לי את השם של הטופס מעולה והנה יש לנו פה טופס ונתחיל לעצב אותו בצורה ממש פשוטה ניקח כאן קודם כל איזשהו צבע רקע כמובן עדיף היה אולי לייצר איזשהו בייס פורם בואו ניקח פה משהו פשוט

  3. 01:24

    ניקח איזשהי לייבל שאומרת למשתמש, Enter relevant message אנחנו רוצים לשלוח, הטופס עצמו אנחנו לא רוצים שיהיה כתוב עליו פורום אחד, אנחנו רוצים שאיך שהוא עולה הוא ייפתח במרכז המסך, לא ניתן למשתמש את האופציה to maximize, לא ניתן למשתמש את האופציה להגדיל את הטופס, יש לנו פה פורום בורדר

  4. 02:06

    סטייל פיקסט שלא ישננו פה את הגרפיקה שלו, נגדיר אולי לטופס איזשהו גופן קצת יותר גדול. ניקח פה 12, bold, יופי.

  5. 02:26

    עכשיו הוא נראה קצת יותר מרשים ויש לנו פה את ההודעה שברצוננו לשלוח. וההודעה כמובן מגיעה מתיבת טקסט. אז הנה יש לנו תיבת טקסט, עושים אותה כבייסליין מיושר ואנחנו רוצים איזשהו לחצן send.

  6. 02:48

    בואו ניקח את הלחצן הזה, הנה יש לנו פה לחצן send, כמובן אני סתם זורק איזה עיצוב מאוד פשוט btn send כתוב על הלחצן את המחרוזת send ויש לנו פיבת טקסט שנקראת txt message יש לנו label שנקראת lbl message בואו נעשה פה אולי משהו כזה נשים את זה פה נדר אותם עם הבייסליין והסגול

  7. 03:48

    שהטקסטים יהיו מיושרים ויש לנו עכשיו את הרכיבים הפשוטים שאנחנו יכולים להתחיל לתקשר איתם בצ'אט. עכשיו כאשר אנחנו מקבלים הודעה בחזרה מה אנחנו רוצים לעשות אנחנו רוצים להציג אותה באיזשהי ליסט בוקס אז בואו ניקח פה רכיב ליסט בוקס נזרוק על הטופס הנה הרכיב נמצא כאן נפתח

  8. 04:20

    את הליסט בוקס בצורה כזאת ונקרא לליסט בוקס הזאת lst פה סיימנו לבנות את היוזר אינטרפייס של הלקוח אני לא רואה עוד משהו שאני צריך כאן אולי נבדוק את הטאבים זה טאב אינדקס אחד זה טאב אינדקס 2 ו3 אז זה בסדר בואו נלך לטופס ונגדיר שכשלוחצים עליו אז אנחנו רוצים שהאיפה זה אקספט בטון

  9. 04:58

    יהיה הלחצן btn send והאמת יש לנו כאן אפשרות לעוד דבר שכדאי לנו לעשות, אז זה יהיה די נכון לעשות אותו, וזה קונקט ודיסקונקט.

  10. 05:18

    אז מה שנעשה, ניקח גרופ בוקס ונעשה פה איזשהו טריק עם ה-UI. נזרוק בתוך הגרופ בוקס את כל ה-UI הזה, כלומר בוקס זה בוקס צ'אט, יש לנו כאן את הכותרת אנחנו לא צריכים, ואת כל היוזר אינטרפייס הזה נזרוק לתוך הבוקס.

  11. 05:58

    תכף תראו מה אנחנו עושים איתה. נגדיר שהיא בדיוק במימדים האלה ונצמיד אותה לראש של הטופס. נשאיר טיפה מקום כי אנחנו רוצים להגדיר איזשהו תפריט.

  12. 06:20

    בואו ניקח פה מניו. הנה יש לנו פה מניו סטריפ ואנחנו רוצים שתהיה לנו את האפשרות להתחבר. למה התפריט נמצא כאן?

  13. 06:36

    נחזור נבחר את הטופס מניו סטריפ על הטופס שבו למעלה ויש לנו כאן איזושהי אופריישן שניתנת לביצוע דבר ראשון אנחנו יכולים to connect ואנחנו יכולים גם to disconnect בנוסף אנחנו יכולים להגדיר כאן ספרייטור תפריט אחרון יהיה אקזיט לסגור את הטופס שמות אנחנו רוצים שזה יהיה MNU קונקט, אנחנו רוצים בדיסקונקט

  14. 07:24

    להתחיל אותו בדיסקונקט, אנחנו רוצים שיהיה לנו פה MNU אקזיט, ובייסיקלי ה-UI עכשיו אפשר להגיד שהוא מוכן, צמצם את הטופס, ואז יש לנו גם אפשרות להתחבר ולהתנתק על ידי הלקוח, שזאת נקודה שהיא חשובה פחות או יותר, ונעלה טיפה למעלה, הצבנו ביחד איזשהו טופס שיכול לשמש לנו user interface לצ'אט

  15. 08:03

    טוב מה הלוגיקה של הטופס אז בואו נחזור ל-solution explorer ואנחנו יודעים שאנחנו צריכים להשתמש עם ה-communicator library זה אומר שאנחנו צריכים לגשת ל-references של ה-client to add reference ולצרף את ה-communicator library עכשיו נקודה חשובה מה שאני רואה ששכחתי זה לגשת לטופס עצמו,

  16. 08:35

    לאיזושהי מחלקה בפרויקט של הטופס ולשנות את ה-Namespace Client ל-Chat, כמו שאמרנו בהתחלה, שיהיה לנו את אותו ה-Namespace בכל הפרויקטים שקשורים לאותה המערכת.

  17. 08:49

    אוקיי, עכשיו זה בסדר. טוב, מה אנחנו רוצים לעשות ב-Client? דבר ראשון, מה שאנחנו רוצים זה שבמידה והיוזר מרים לנו את הטופס, מריץ את התוכנית והטופס עולה אנחנו לא רוצים שהוא יוכל לעבוד עם הצ'אט לפני שהוא עושה קונקט לכן יש לנו את

  18. 09:13

    הגרופבוקס אנחנו יכולים להגדיר את כל הגרופבוקס כ-Enabled False וזה אומר שלא ניתן לעבוד בכלל עם מה שבתוכה איפה אנחנו מגדירים EnabledTrue אחרי שאנחנו מבצעים קונקט אז בואו נלך לתפריט קונקט דאבל קליק נגיע לטופס ואנחנו עכשיו נמצאים ברמה של הטופס עצמו איזה איזה אובייקטים אנחנו צריכים ברמת הטופס?

  19. 09:43

    אנחנו צריכים ברמת הטופס את private tcp listener שהתפקיד שלו לא tcp listener tcp client שהתפקיד שלו זה להביא לנו את הסוקט ליזום התחברות ולהביא לנו את הסוקט אולי היה כדאי גם את זה להוציא למחלקה חיצונית אבל אני אתן לכם לחשוב על זה לבד בואו נפתח פה אותו tcp client והדבר הבא שאנחנו רוצים זה את אובייקט ה-com והנה אנחנו רואים שאנחנו אוטומטית מכירים אותו גם

  20. 10:21

    בגלל שהבאנו את ה-reference וגם בגלל שה-namespace הוא אותו ה-namespace זה יהיה ה-communicator אנחנו לא רוצים לפתוח אובייקט באזור הגלובלי אלא אנחנו רוצים לפתוח אובייקט בקונקט קודם כל נלך ל-tcp client נפתח אובייקט חדש לאחר מכן נבצע התחברות

  21. 10:44

    על ידי פונקציית קונקט של ה-tcp client שלהזכירכם מקבלת איפה הסרבר נמצא בגלל שהכל רץ כרגע על המחשב שלי על המחשב המקומי אז נגדיר את ה-localhost במציאות הייתי אמור להגדיר כאן איזה שהוא IP אמיתי שבו יושב הסרבר פורט נמציא את אותו הפורט של מקודם שעבד לנו טוב 8085 ועכשיו התחברנו בנקודה הזאת נוסד קו תקשורת לסרבר ולסרבר יש סוקט שנבנה

  22. 11:20

    שם ואנחנו גם קיבלנו את הסוקט אבל עכשיו אנחנו יכולים לפתוח את אובייקט הקומוניקטור שנקרא underline.com בואו נפתח את האובייקט הזה וניתן לו את הסוקט שלנו tcp.client.client זה השם המוזר שדיברנו עליו פעם ואחרי שהכל יתחבר אנחנו יכולים להירשם לאירוע האירוע נקרא got message, ושימו לב ששכחתי משהו חמור, לא כל כך חמור, אבל לפי האייקון אני רואה ששכחתי להגדיר כאן את המילה event.

  23. 12:11

    לא לעשות דבר כזה, כי אנחנו לא רוצים שיהיה ניתן לעשות שווה, אלא רק פלוס שווה, וזה כמובן צריך להתנהג כמו event רגיל. אז עכשיו אנחנו יכולים לראות לפי האייקון שיש לנו אייקון של ברק.

  24. 12:27

    פלוס שווה טאב טאב יש לנו כאן את זה אפשר להיפטר לעשות קצת יותר מה שנקרא קלין קוד נעיף את זה נעיף את זה וזה האירוע. מתי האירוע הזה מועלה?

  25. 12:48

    כאשר אובייקט הקומיניקטור קיבל הודעה מהצד השני. מי זה הצד השני שלנו? הסרבר אנחנו קליינט אז כאשר הקליינט מקבל הודעה מהסרבר הקומיניקטור ליתר דיוק הוא מעלה באירוע את ההודעה ואנחנו צריכים להאזין מה אנחנו רוצים לעשות כשאנחנו מקבלים את ההודעה אנחנו רוצים להוסיף את ההודעה

  26. 13:12

    לליסט אז יש לנו פה את ה-list messages נקודה items נקודה בוא נלך ל-insert למה insert ולא add כי אני יכול ב-insert להגיד תכניס לי את זה בבקשה למקום הראשון מי זאת ההודעה e.message כי אנחנו פה בעולם האירועים וזאת פונקציית ה-callback שהאירוע מאזין לה.

  27. 13:38

    אוקיי, דבר אחרון שאנחנו צריכים לעשות ולאפשר את ה-UI. Box Chat Enabled שווה True. MNU Connect Enabled False שלא ניתן ללחוץ על ה-Connect בלי ללחוץ על MNU Disconnect Enabled שווה True.

  28. 14:05

    למעשה מה שאפשר לעשות זה פשוט מאוד דבר כזה. אנחנו רוצים להכניס true ב-enabled של הגרופוקס וב-enabled של התפריט disconnect כי עשינו כרגע קונקט ולבטל את אובייקט ה-disconnect זה נעשה ראשון זה אומר שאנחנו צריכים גם ללכת ועל ההתחלה להגדיר שה-disconnect ה-enabled שלו הוא false זהו נחזור בחזרה מה עוד אנחנו צריכים לעשות

  29. 14:47

    כאן בוא נראה כן לוחצים על דיסקונקט בואו נלך לדיסקונקט דאבל קליק ברגע שלחצו לנו על דיסקונקט מה אנחנו רוצים לעשות מישהו רוצה להתנתק אוקיי אם הוא רוצה להתנתק אז אנחנו צריכים לגשת ל-com unicator ו-to dispose it להיפטר ממנו אנחנו רוצים לגשת ל-tcp client ו-to close it אנחנו רוצים לגשת ולשנות את ה-UI זאת אומרת שניקח את שני החבריה האלה

  30. 15:36

    נדביק אותם פה וניגש ל-MNU קונקט group דיסקונקט ובוקס פלס יוזר לא יוכל ללחוץ עכשיו עוד פעם על הדיסקונקט אלא הוא יוכל אם הוא רוצה ללחוץ על הקונקט בסדר אז בואו ננקה פה מרחבי שמות ונראה לי שהטופס הזה פחות או יותר done אם לא שכחתי משהו קריטי אנחנו כמובן נצטרך לטפל בכל הנושא של טרדינג אבל תזכרו את זה לעוד מעט סיימנו את הקליינט

  31. 16:22

    את הבסיס שלו לפחות ושימו לב שהקוד יחסית הוא קצר כי רוב העבודה התבצעה בתוך ה-Communicator שמבצע את התקשורת. עכשיו אנחנו יכולים להוסיף את ה-Server.

  32. 16:37

    אז בואו נצרף פרויקט, נקרא לו Server, גם הוא יהיה Windows Forms, יותר מרשים שה-Server יהיה לו איזשהו UI במקום קונסול, ויהיה ה-Server שלנו.

  33. 16:51

    שימו לב שהוא באותה תקייה של ה-Solution של ה-Chat. Next, נקרא לטופס הזה Server Form, שימו לב שאני נותן דגש חזק מאוד על שמות של כל דבר, קבצים, פרויקטים, ניימספייס, משתנים.

  34. 17:12

    ניימספייס הפעם אני לא אשכח להגדיר אותו ראשון, צ'אט, נשנה כל הניימספייס כולל ניימספייסים עתידיים ואנחנו יכולים לראות שהרבה מהעיצוב של הסרבר הוא דומה לעיצוב של הקליינט.

  35. 17:35

    אז אנחנו הולכים לעשות פה טיפה קופי פייסט של קונטרולים מהקליינט בשביל לתקתק את זה מהר. בואו רק נעצב את הטופס לפני זה. קצת במרכז המסך, אי אפשר לעשות לך מקסימייזד, אי אפשר להזיז את הגבולות שלך ופתאום לעוות את הטופס.

  36. 17:58

    בדרך כלל עושים את זה לטפסים שיש להם UI סגור, קבוע. אנחנו רוצים את הגופן שלו טיפה להגדיל, וכי חשוב כמובן, או תמונת רקע, או איזשהו צבע רקע, נעשה צבע רקע שונה כדי שנוכל לדעת שזה הסרבר ורק לא הצבע הזה.

  37. 18:30

    בואו ניקח גולד, לא, אוי ואבוי, אני הייתי עיוור לרגע. ניקח משהו קצת יותר טוליבי, יופי. בסדר, הנה הסרבר ואנחנו רוצים להעתיק אליו את ה-UI של הטופס.

  38. 18:51

    אז, אה, רגע, אני רואה ששכחתי לבנות את האקזיט. נלך לאקזיט. קלוז. השלמנו את האקזיט.

  39. 19:01

    טוב, בואו נלך ל-UI של הטופס, נשמור את הכל. דרך אגב, כדאי לעשות איזה פורמטינג ולוק קונטרולס, כדי שהוא ינעל לנו את הכל.

  40. 19:13

    קונטרול A, תבחר לי את הכל, קונטרול C, בואו נחזור לפה, נפתח את הטופס, קונטרול V, בבת אחת יש לנו פה את כל ה-UI ונוריד את הלוק קונטרולס כי גם זה הוא עתק איתנו.

  41. 19:34

    ועכשיו בואו נעשה את הסרבר עוד יותר פשוט מאשר הקליינט. אנחנו כרגע נשאיר פה את המסג' שנוכל לשלוח ללקוחות מסג' אבל לא נשתמש בה כרגע. נצמצם טיפה את הטופס.

  42. 19:51

    גם כאן יש לנו קונקט ודיסקונקט, אז בייסיקלי הוא נראה מאוד מאוד דומה. אפשר להעיף את זה באיזשהו שלב אם לא רוצים לראות. בסדר.

  43. 20:03

    מה אנחנו רוצים לעשות בצד של הסרבר? מצד של הסרוור אנחנו רוצים לבצע פעולות אחרות שמבצעים התחברות והתנתקות. קודם כל הסרוור גם כן צריך את ה-Communicator Library.

  44. 20:21

    זה מאפשר לשלוח ולקבל הודעות. בואו נלך ל-Add Reference, Communicator Library, אוקיי, בבקשה, יש לנו.

  45. 20:31

    הדבר הבא שאנחנו רוצים זה לסגור את Exit, שלא נשכח, ו-Close, אחלה. הדבר הבא שאנחנו רוצים זה קונקט מה אנחנו רוצים לעשות בסרבר כאשר אנחנו מבצעים קונקט בסרבר אנחנו צריכים לפתוח את האובייקט tcp listener private יש לנו כאן את tcp listener ואנחנו רוצים בקונקט לגשת לtcp listener להכניס אובייקט חדש אליו ואנחנו רוצים לקחת את IP Address כמו שעשינו

  46. 21:22

    בהדגמה ההיא ואגיד שהוא יאזין למחשב הנוכחי לאותו פורט שהלקוח מכיר 8085. אנחנו אמורים לבגור, בואו נראה את זה, יופי. הדבר הבא, tcp-listener.start תעלה לאוויר ותתחיל להאזין.

  47. 21:54

    בנוסף אנחנו רוצים שיהיה לנו פה איזשהו טראד שיאזין, כל הזמן יאזין ללקוחות חדשים. למה אנחנו רוצים את זה בתור טראד? כי גם ההזנה ללקוח חדש זה בלוקינג אופריישן.

  48. 22:07

    לא רוצים לתקוע את ה-UI, חייבים להוסיף פה טרד פריווט פרד, נקרא לזה listen to new clients thread.

לקורס המלא: קורס תכנות מתקדם ב‑#C ודוט-נט

ההרצאה הקודמת: Client-Server Architecture - חלק 1

ההרצאה הבאה: תרגילים על Client-Server Architecture ב-#C

הרצאות קשורות מקורסים אחרים

  • Client-Server Projects
  • הדגמה של NAP Client
  • Linux Container on Server 2019
  • התקנה ידנית של SCCM CLIENT

קורסים נוספים במסלול

  • קורס WinForms - תוכנות רגילות בווינדוס
  • פרויקט מעשי ב-#C - בונים מחשבון פשוט
  • פרויקט מעשי ב-#C - ספר טלפונים
  • פרויקט מעשי ב-#C - תוכנת צייר
  • קורס ADO.NET - חיבור אתר למסד נתונים
  • קורס WCF - תקשורת למתקדמים בדוט-נט