JAVA, NIO, Selector לא מצליח לפתור את הבאג
מטרת התרחיש היא לבדוק הדלקה וכיבוי של השרת.
התרחיש:
הבאג:
אני מקבל ConcurrentModificationException במעבר על הלולאה שסוגרת את כל ה - channels.
אין לי מושג למה אני מקבל את ה - exception הזה.
שמתי לב שבזמן הסגירה של ה - channels, ה - selector מתעורר, ואני לא מצליח להבין למה.
כשאני מכבה את השורה ב - client שמבצעת close ל - socket לאחר הסגירה שלו מצד השרת, הבאג נעלם, ולכן העליתי את ההשערה שמאיזושהי סיבה close מצד ה-client גורם ל - select להתעורר. זה מפתיע כי ה - key שמקושר לאותו socket כבר עבר cancel.
כשה - select מתעורר אני בודק מי נמצא ב - selectedKeys. אם הספקתי לסגור את ה - serverSocketChannel, הקבוצה הזו תהיה ריקה. אם לא הספקתי לסגור אותו, המפתח שלו יהיה היחיד בקבוצה.
אבחנה נוספת היא שאם אני מעתיק את כל המפתחות מתוך ה - selector.keys לתוך רשימה נפרדת, אני לא אקבל את אותו CME. זה מרגיש לי כמו workaround כי אני עדיין לא מבין מי נכנס לset הזה ונוגע בו בזמן שאני עובר עליו. הייתי משער שה - selector עושה זאת אחרי שהוא מתעורר אבל אז אני עדיין צריך להבין מי מעיר אותו.
לסיכום:
המסקנה שלי היא שברגע שה - client סוגר את ה - socket ה - selector מתעורר, אף על פי שהתבצע cancel ל - channel שמשוייך לאותו client.
ברגע שה - selector מתעורר, הוא נוגע איכשהו ב - key שלו וגורם ל - CME.
זה מוביל לשתי שאלות:
http://pastebin.com/2xP7t8qu
הדפסות לאחר הרצה (שימו לב שבאחת ההדפסות רשימת המפתחות שאיתן ה - selector התעורר היא ריקה, ובשנייה היא מלאה):
http://pastebin.com/qw6j9bTH
אם למישהו יש רעיון למה שקורה כאן, אשמח לכל עזרה.
מטרת התרחיש היא לבדוק הדלקה וכיבוי של השרת.
התרחיש:
- פותח thread עבור שרת.
- יוצר Selector ויוצר ServerSocketChannel ומצמד אותו ל - Selector.
- ה - ServerSocketChannel אחראי לקבל חיבורים נכנסים. בכל חיבור הוא מייצר SocketChannel חדש ומצמד אותו ל - Selector. (אותו Selector מאזין גם ל - ServerSocket וגם לכל ה - Socket-ים).
- כל אחד מה - SocketChannel-ים קורא מידע מהרשת וכותב אותו למערך שלא עושה שום דבר.
- פותח עשרים thread-ים עבור ה - clients. כל אחד מהם מתחבר לשרת, ומבצע read. ברגע שה - read חוזר, הוא מוודא שהתקבל 1- (כלומר השרת סגר את החיבור), ואז סוגר את ה - socket.
- ב - thread הראשי ממתין שלוש שניות כדי שכל החיבורים יתייצבו ואז עובר על ה - selector.keys() ועבור כל אחד מהם מבצע close ל - channel ואז cancel.
- מבצע wakeup לselector כדי שיסיים את הלולאה שלו ויסגור את השרת
הבאג:
אני מקבל ConcurrentModificationException במעבר על הלולאה שסוגרת את כל ה - channels.
אין לי מושג למה אני מקבל את ה - exception הזה.
שמתי לב שבזמן הסגירה של ה - channels, ה - selector מתעורר, ואני לא מצליח להבין למה.
כשאני מכבה את השורה ב - client שמבצעת close ל - socket לאחר הסגירה שלו מצד השרת, הבאג נעלם, ולכן העליתי את ההשערה שמאיזושהי סיבה close מצד ה-client גורם ל - select להתעורר. זה מפתיע כי ה - key שמקושר לאותו socket כבר עבר cancel.
כשה - select מתעורר אני בודק מי נמצא ב - selectedKeys. אם הספקתי לסגור את ה - serverSocketChannel, הקבוצה הזו תהיה ריקה. אם לא הספקתי לסגור אותו, המפתח שלו יהיה היחיד בקבוצה.
אבחנה נוספת היא שאם אני מעתיק את כל המפתחות מתוך ה - selector.keys לתוך רשימה נפרדת, אני לא אקבל את אותו CME. זה מרגיש לי כמו workaround כי אני עדיין לא מבין מי נכנס לset הזה ונוגע בו בזמן שאני עובר עליו. הייתי משער שה - selector עושה זאת אחרי שהוא מתעורר אבל אז אני עדיין צריך להבין מי מעיר אותו.
לסיכום:
המסקנה שלי היא שברגע שה - client סוגר את ה - socket ה - selector מתעורר, אף על פי שהתבצע cancel ל - channel שמשוייך לאותו client.
ברגע שה - selector מתעורר, הוא נוגע איכשהו ב - key שלו וגורם ל - CME.
זה מוביל לשתי שאלות:
- מדוע ה - selector מתעורר בזמן סגירת ה - client (אם בכלל זה מה שקורה) ומדוע ה - selectedKeys שלו ריק או מכיל לכל היותר את המפתח של ServerSocketChannel?
- מי עוד נוגע באותו keySet ולכן גורם ל - CME?
http://pastebin.com/2xP7t8qu
הדפסות לאחר הרצה (שימו לב שבאחת ההדפסות רשימת המפתחות שאיתן ה - selector התעורר היא ריקה, ובשנייה היא מלאה):
http://pastebin.com/qw6j9bTH
אם למישהו יש רעיון למה שקורה כאן, אשמח לכל עזרה.