Smart-World Surf

יחידה 9: תכנות רשת

תקשורת בין יישומים ברשת באמצעות שקעים.
פרוטוקולי TCP/UDPשקעי שרת ולקוחתקשורת נתוניםיישומים מבוזרים

ברוכים הבאים ליחידת "תכנות רשת" בקורס "תכנות מתקדם בשפת Java" (20554). יחידה זו חיונית להבנת האופן שבו יישומים שונים, הפועלים על מחשבים נפרדים, יכולים לתקשר ביניהם דרך הרשת. נצלול לעולם התקשורת מבוססת שקעים (Sockets), נכיר את הפרוטוקולים המרכזיים TCP ו-UDP, ונלמד כיצד לבנות יישומים מבוזרים ב-Java שיכולים לדבר זה עם זה.

יסודות תקשורת רשת ב-Java

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

מודל לקוח-שרת (Client-Server Model): ארכיטקטורת רשת שבה שרת מספק שירותים למספר לקוחות, כאשר הלקוחות יוזמים את התקשורת והשרת מגיב לבקשותיהם.
יישום מבוזר (Distributed Application): יישום שרכיביו פועלים על מספר מחשבים מחוברים לרשת, ומתקשרים ביניהם כדי להשלים משימה משותפת.

פרוטוקולי תקשורת: TCP ו-UDP

כדי שיישומים יוכלו לתקשר, עליהם להסכים על סט כללים – פרוטוקול. שני הפרוטוקולים המרכזיים בשכבת התעבורה הם TCP ו-UDP, ולכל אחד מהם מאפיינים שונים המשפיעים על בחירת השימוש בו.

TCP (Transmission Control Protocol)

חיבורי: דורש יצירת חיבור (לחיצת יד משולשת) לפני העברת נתונים.
אמין: מבטיח הגעת נתונים, סדר נכון, וטיפול בשגיאות (שידור חוזר).
מבוסס זרם (Stream-based): הנתונים נשלחים כזרם רציף של בתים.
איטי יחסית: בשל תקורה של אמינות ובקרת זרימה.
שימושים: גלישה באינטרנט (HTTP/HTTPS), העברת קבצים (FTP), דואר אלקטרוני (SMTP).

UDP (User Datagram Protocol)

חסר חיבור (Connectionless): שולח חבילות נתונים (דאטאגרמות) ללא יצירת חיבור מוקדמת.
לא אמין: לא מבטיח הגעת נתונים, סדר, או טיפול בשגיאות.
מבוסס חבילות (Datagram-based): כל חבילה עצמאית.
מהיר: בשל מיעוט תקורה.
שימושים: סטרימינג וידאו/אודיו, משחקי רשת, DNS.

שקעים (Sockets) ב-Java

שקע הוא נקודת קצה לתקשורת בין תהליכים (Inter-Process Communication - IPC) ברשת. ב-Java, אנו משתמשים במחלקות מיוחדות ליצירה וניהול של שקעים.

שקע (Socket): מנגנון תוכנה המאפשר לתהליכים שונים (בדרך כלל על מכונות שונות) לתקשר ביניהם דרך הרשת. הוא משמש כנקודת קצה לחיבור.

שקעי שרת ולקוח ב-Java

עבור תקשורת TCP, נשתמש בשתי מחלקות עיקריות:

  • ServerSocket: מחלקה בצד השרת, המאזינה לחיבורים נכנסים בפורט ספציפי. כאשר לקוח מתחבר, ה-ServerSocket יוצר אובייקט Socket חדש לטיפול בחיבור זה.
  • Socket: מחלקה המשמשת הן בצד הלקוח (ליצירת חיבור לשרת) והן בצד השרת (לייצוג החיבור הספציפי עם לקוח לאחר שנוצר). דרך אובייקט זה מתבצעת העברת הנתונים.

תהליך תקשורת TCP בסיסי

צד השרת:

  1. יצירת ServerSocket בפורט מסוים: new ServerSocket(port).
  2. האזנה לחיבורים נכנסים: serverSocket.accept(). שיטה זו חוסמת עד שלקוח מתחבר, ומחזירה אובייקט Socket חדש.
  3. קבלת זרמי קלט/פלט מה-Socket: socket.getInputStream() ו-socket.getOutputStream().
  4. קריאה וכתיבה של נתונים דרך הזרמים.
  5. סגירת ה-Socket וה-ServerSocket.

צד הלקוח:

  1. יצירת Socket וחיבור לשרת: new Socket(serverAddress, port).
  2. קבלת זרמי קלט/פלט מה-Socket: socket.getInputStream() ו-socket.getOutputStream().
  3. קריאה וכתיבה של נתונים דרך הזרמים.
  4. סגירת ה-Socket.
פורט (Port): מספר לוגי המשמש לזיהוי יישום או שירות ספציפי במחשב, ומאפשר למערכת ההפעלה לנתב חבילות נתונים ליישום הנכון.

טיפול בחיבורים מרובים וניהול משאבים

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

טיפול בלקוחות מרובים באמצעות תהליכונים

כאשר השרת מקבל חיבור חדש (serverSocket.accept()), הוא יכול להקצות תהליכון חדש (או להשתמש ב-ExecutorService) לטיפול בלקוח זה. כך, השרת הראשי יכול להמשיך להאזין לחיבורים חדשים, בעוד התהליכונים הנפרדים מטפלים בתקשורת עם הלקוחות הקיימים.

טיפול בשגיאות וסגירת משאבים: זהו אחד הנושאים הקריטיים ביותר בתכנות רשת, ומופיע לעיתים קרובות במבחנים. יישומי רשת חשופים לכשלים רבים (ניתוקי רשת, שגיאות קלט/פלט, קריסת צד שני). חובה להשתמש בבלוקי try-catch-finally או, עדיף, ב-try-with-resources כדי להבטיח שכל המשאבים (שקעים, זרמים) נסגרים כראוי, גם במקרה של שגיאה. אי סגירת משאבים עלולה להוביל לדליפות זיכרון, חסימת פורטים, וחוסר יציבות של היישום.

שאלות לדיון

  • תאר מצב שבו היית בוחר להשתמש בפרוטוקול UDP על פני TCP, והסבר מדוע.
  • כיצד ניתן להבטיח ששרת Java יוכל לטפל בעשרות לקוחות בו-זמנית מבלי לקרוס או להאט משמעותית?
  • אילו אתגרים אבטחתיים קיימים בתכנות רשת מבוסס שקעים, וכיצד ניתן להתמודד איתם ב-Java?
  • הסבר את חשיבות השימוש ב-try-with-resources בעבודה עם שקעים וזרמים בתכנות רשת.

נקודות לתשובת מודל

  • בחירת פרוטוקול: UDP מתאים ליישומים הדורשים מהירות וסבילות לאובדן נתונים (למשל, סטרימינג בזמן אמת, משחקים מקוונים), שבהם שידור חוזר של חבילות עלול לגרום לעיכובים בלתי קבילים. TCP מתאים ליישומים הדורשים אמינות מלאה וסדר נתונים (למשל, העברת קבצים, דואר אלקטרוני).
  • טיפול בלקוחות מרובים: שימוש בתהליכונים (Threads) או ב-ExecutorService. כל חיבור חדש (Socket) מטופל על ידי תהליכון נפרד, המאפשר לשרת להמשיך להאזין לחיבורים נוספים. יש לדון בניהול משאבי תהליכונים (pool size).
  • אתגרים אבטחתיים: האזנה (eavesdropping), התקפות מניעת שירות (DoS), הזרקת נתונים זדוניים. התמודדות: שימוש ב-SSL/TLS (למשל, SSLSocket/SSLServerSocket) להצפנה ואימות, סינון קלט, הגבלת קצב חיבורים.
  • חשיבות try-with-resources: מבטיח שמשאבים (כמו Socket, ServerSocket, InputStream, OutputStream) ייסגרו אוטומטית בסיום הבלוק, גם אם מתרחשת חריגה. זה מונע דליפות משאבים, חסימת פורטים, ומבטיח יציבות יישומים.
מצאתם טעות או שחסר משהו?
→ הקודמת
ממשקי משתמש גרפיים (GUI)
הבאה ←
דפוסי תכנון ונושאים מתקדמים