מדריך לערוץ שקע אסינכרוני NIO2

1. סקירה כללית

במאמר זה נדגים כיצד לבנות שרת פשוט ולקוח שלו באמצעות ממשקי ה- API של ערוץ Java 7 NIO.2.

נסתכל על AsynchronousServerSocketChannel ו AsynchronousSocketChannel שיעורים שהם מחלקות המפתח המשמשות ליישום השרת והלקוח בהתאמה.

אם אתה חדש ב- API של ערוץ NIO.2, יש לנו מאמר היכרות באתר זה. תוכלו לקרוא אותו באמצעות קישור זה.

כל הכיתות הדרושות לשימוש בממשקי API של ערוץ NIO.2 מאוגדות ב java.nio.channels חֲבִילָה:

ייבא java.nio.channels. *;

2. השרת עם עתיד

מופע של AsynchronousServerSocketChannel נוצר על ידי קריאה לממשק ה- API הפתוח הסטטי בכיתתו:

AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open ();

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

server.bind (InetSocketAddress חדש ("127.0.0.1", 4555);

באותה מידה יכולנו לעבור באפס כך שישתמש בכתובת מקומית ונקשר לנמל שרירותי:

server.bind (null);

לאחר הכריכה, לְקַבֵּל API משמש ליזום קבלת חיבורים לשקע הערוץ:

Future acceptFuture = server.accept ();

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

לאחר מכן נוכל להשתמש ב- לקבל ממשק API לשאילתה לתגובה מה- עתיד לְהִתְנַגֵד:

עובד AsynchronousSocketChannel = future.get ();

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

עובד AsynchronousSocketChannel = acceptFuture.get (10, TimeUnit.SECONDS);

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

בואו ניצור שיטה שנקראת runServer במסגרתו נעשה את ההמתנה ונעבד את כל ההודעות הנכנסות:

חלל ריק runServer () {clientChannel = acceptResult.get (); if ((clientChannel! = null) && (clientChannel.isOpen ())) {while (true) {ByteBuffer buffer = ByteBuffer.allocate (32); ReadResult עתידי = clientChannel.read (חיץ); // לבצע חישובים אחרים readResult.get (); buffer.flip (); עתיד לכתוב - תוצאות = clientChannel.write (חיץ); // לבצע חישובים אחרים writeResult.get (); buffer.clear (); } clientChannel.close (); serverChannel.close (); }}

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

ואז, בכל פעם שאנחנו קוראים או כותבים, אנחנו יכולים להמשיך לבצע כל קוד אחר וכשאנחנו מוכנים לעבד את התוצאה, אנו קוראים לקבל() ממשק API ב- עתיד לְהִתְנַגֵד.

כדי להפעיל את השרת, אנו מתקשרים לבנאי שלו ואז ל- runServer שיטה בפנים רָאשִׁי:

main static public void (String [] args) {AsyncEchoServer server = AsyncEchoServer new (); server.runServer (); }

3. השרת עם CompletHandler

בחלק זה נראה כיצד ליישם את אותו שרת באמצעות ה- CompletHandler גישה ולא א עתיד גִישָׁה.

בתוך הבנאי אנו יוצרים AsynchronousServerSocketChannel ולקשור אותו לכתובת מקומית באותו אופן שעשינו בעבר:

serverChannel = AsynchronousServerSocketChannel.open (); InetSocketAddress hostAddress = חדש InetSocketAddress ("localhost", 4999); serverChannel.bind (hostAddress);

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

ל למנוע מהלולאה לרוץ בלי סוף, אנו קוראים System.in.read () בסוף שלה לחסום ביצוע עד לקריאת חיבור נכנס מזרם הקלט הסטנדרטי:

בעוד (נכון) {serverChannel.accept (null, CompletionHandler חדש () {@Override public void הושלם (AsynchronousSocketChannel תוצאה, קובץ מצורף) {if (serverChannel.isOpen ()) {serverChannel.accept (null, this);} clientChannel = תוצאה; אם ((clientChannel! = null) && (clientChannel.isOpen ())) {ReadWriteHandler handler = new ReadWriteHandler (); ByteBuffer buffer = ByteBuffer.allocate (32); Map readInfo = HashMap new (); readInfo.put ( "פעולה", "לקרוא"); readInfo.put ("חיץ", חיץ); clientChannel.read (חיץ, readInfo, מטפל);}} @ ביטול ציבורי בטל נכשל (Excrow זמין, קובץ מצורף אובייקט) {// שגיאת תהליך }}); System.in.read (); }

כאשר נוצר חיבור, ה- הושלם שיטת ההתקשרות CompletHandler של פעולת הקבלה נקראת.

סוג ההחזרה שלו הוא מופע של AsynchronousSocketChannel. אם ערוץ שקע השרת עדיין פתוח, אנו קוראים ל- לְקַבֵּל API שוב כדי להתכונן לחיבור נכנס נוסף תוך שימוש חוזר באותו מטפל.

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

הנקודה בה אנו יכולים להתחיל פעולות קריאה וכתיבה היא בתוך ה- הושלם API להתקשרות חוזרת של לְקַבֵּל המטפל במבצע. שלב זה מחליף את הגישה הקודמת בה סקרנו את הערוץ עם ה- לקבל ממשק API.

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

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

ראשית, בואו נסתכל על ה- ReadWriteHandler מעמד:

בכיתה ReadWriteHandler מיישם את CompletingHandler {@ ביטול הריק הציבורי הושלם (תוצאה שלמה, קובץ מצורף) {Map actionInfo = קובץ מצורף; מחרוזת פעולה = (מחרוזת) actionInfo.get ("פעולה"); if ("read" .equals (action)) {ByteBuffer buffer = (ByteBuffer) actionInfo.get ("buffer"); buffer.flip (); actionInfo.put ("פעולה", "כתוב"); clientChannel.write (חיץ, actionInfo, זה); buffer.clear (); } אחרת אם ("כתוב" .equals (פעולה)) {ByteBuffer buffer = ByteBuffer.allocate (32); actionInfo.put ("פעולה", "לקרוא"); actionInfo.put ("חיץ", חיץ); clientChannel.read (חיץ, actionInfo, זה); }} הריק הציבורי של @Override נכשל (excrowable לזרוק, קובץ מצורף) {//}}

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

לאחר מכן, נראה כיצד משתמשים בפרמטרים אלה.

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

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

אם זה א לִכתוֹב הפעולה שהסתיימה זה עתה, אנו קוראים לקרוא API שוב כדי להכין את השרת לקבל הודעה נכנסת נוספת.

4. הלקוח

לאחר הגדרת השרת, כעת אנו יכולים להגדיר את הלקוח על ידי התקשרות ל לִפְתוֹחַ ממשק API ב- AsyncronousSocketChannel מעמד. שיחה זו יוצרת מופע חדש של ערוץ שקע הלקוח שבו אנו משתמשים כדי ליצור חיבור לשרת:

לקוח AsynchronousSocketChannel = AsynchronousSocketChannel.open (); InetSocketAddress hostAddress = חדש InetSocketAddress ("localhost", 4999) עתיד עתידי = client.connect (hostAddress);

ה לְחַבֵּר פעולה לא מחזירה דבר בהצלחה. עם זאת, אנו עדיין יכולים להשתמש ב- עתיד התנגד לפקח על מצב הפעולה האסינכרונית.

בוא נקרא לקבל ממשק API להמתנה לחיבור:

future.get ()

לאחר שלב זה, אנו יכולים להתחיל לשלוח הודעות לשרת ולקבל הדים עבור אותו. ה לשלוח הודעה השיטה נראית כך:

מחרוזת ציבורית sendMessage (הודעת מחרוזת) {byte [] byteMsg = מחרוזת חדשה (הודעה) .getBytes (); חיץ ByteBuffer = ByteBuffer.wrap (byteMsg); העתיד לרשום תוצאות = client.write (חיץ); // לעשות קצת חישוב writeResult.get (); buffer.flip (); ReadResult עתידי = client.read (חיץ); // לעשות קצת חישוב readResult.get (); הד מחרוזת = מחרוזת חדשה (buffer.array ()). Trim (); buffer.clear (); הד חוזר; }

5. המבחן

כדי לאשר שיישומי השרת והלקוח שלנו מבצעים על פי הציפייה, אנו יכולים להשתמש במבחן:

@Test הציבור בטל givenServerClient_whenServerEchosMessage_thenCorrect () {String resp1 = client.sendMessage ("שלום"); מחרוזת resp2 = client.sendMessage ("עולם"); assertEquals ("שלום", resp1); assertEquals ("עולם", resp2); }

6. מסקנה

במאמר זה חקרנו את ממשקי ה- API של ערוץ השקע האסינכרוני של Java NIO.2. הצלחנו לעבור את תהליך בניית השרת והלקוח באמצעות ממשקי ה- API החדשים האלה.

תוכל לגשת לקוד המקור המלא של מאמר זה על ידי פרויקט Github.


$config[zx-auto] not found$config[zx-overlay] not found