ความรู้พื้นฐาน
ซิงโครนัสอะซิงโครนัสปิดกั้นการไม่ปิดกั้น
ก่อนอื่นแนวคิดเหล่านี้ง่ายมากที่จะสับสน แต่พวกเขามีส่วนร่วมใน NIO ดังนั้นเรามาสรุปกัน
การซิงโครไนซ์: เมื่อการโทร API ส่งคืนผู้โทรรู้ว่าการดำเนินการนั้นเกิดขึ้นได้อย่างไร
Asynchronous: เปรียบเทียบกับการซิงโครไนซ์ผู้โทรไม่ทราบผลลัพธ์ของการดำเนินการเมื่อการโทร API ส่งคืนและการโทรกลับจะแจ้งผลลัพธ์ในภายหลัง
การบล็อก: เมื่อไม่มีข้อมูลที่จะอ่านหรือไม่สามารถเขียนข้อมูลทั้งหมดระงับการรอเธรดปัจจุบัน
การไม่ปิดกั้น: เมื่ออ่านคุณสามารถอ่านได้มากเท่ากับข้อมูลที่คุณสามารถอ่านและกลับมาได้ เมื่อเขียนคุณสามารถเขียนได้มากเท่ากับข้อมูลที่คุณสามารถเขียนแล้วกลับมา
สำหรับการดำเนินงาน I/O ตามเอกสารของเว็บไซต์ทางการของ Oracle การซิงโครไนซ์และมาตรฐานการแบ่งแบบอะซิงโครนัสคือ "ไม่ว่าผู้โทรจะต้องรอการดำเนินการ I/O ให้เสร็จสมบูรณ์" "การรอให้การดำเนินการ I/O เสร็จสมบูรณ์" ไม่ได้หมายความว่าต้องอ่านข้อมูลหรือต้องเขียนข้อมูลทั้งหมด แต่ผู้โทรต้องรอเมื่อดำเนินการ I/O จริง ๆ เช่นเวลาที่ข้อมูลถูกส่งระหว่างบัฟเฟอร์สแต็กสแต็ก TCP/IP และบัฟเฟอร์ JVM
ดังนั้นวิธีการอ่าน () และการเขียนที่ใช้กันทั่วไปของเราจึงเป็น I/O แบบซิงโครนัส I/O แบบซิงโครนัสแบ่งออกเป็นสองโหมด: การบล็อกและการไม่ปิดกั้น หากเป็นโหมดที่ไม่ปิดกั้นมันจะถูกส่งคืนโดยตรงเมื่อตรวจพบว่าไม่มีข้อมูลที่จะอ่านและการดำเนินการ I/O จะไม่ดำเนินการจริงๆ
โดยสรุปใน Java มีเพียงสามกลไกเท่านั้น: การปิดกั้นแบบซิงโครนัส I/O, I/O ที่ไม่ปิดกั้นแบบซิงโครนัสและ I/O แบบอะซิงโครนัส สิ่งที่เรากำลังพูดถึงด้านล่างคือสองคนแรก JDK1.7 ได้เริ่มแนะนำ I/O แบบอะซิงโครนัสซึ่งเรียกว่า NIO.2
IO ดั้งเดิม
เรารู้ว่าการเกิดขึ้นของเทคโนโลยีใหม่นั้นมาพร้อมกับการปรับปรุงและการปรับปรุงเสมอและการเกิดขึ้นของชวา
I/O แบบดั้งเดิมคือการปิดกั้น I/O และปัญหาหลักคือการสูญเสียทรัพยากรของระบบ ตัวอย่างเช่นในการอ่านข้อมูลของการเชื่อมต่อ TCP เราเรียกวิธีการอ่าน () ของอินพุตสตรีมซึ่งจะทำให้เธรดปัจจุบันถูกระงับและจะไม่ถูกปลุกจนกว่าข้อมูลจะมาถึง เธรดใช้ทรัพยากรหน่วยความจำ (สแต็คเธรดการจัดเก็บ) ในช่วงระยะเวลาของการมาถึงข้อมูล แต่ไม่ทำอะไรเลย นี่คือสิ่งที่คำพูดไปครอบครองหลุมไม่ใช่คนเซ่อ ในการอ่านข้อมูลของการเชื่อมต่ออื่น ๆ เราต้องเริ่มเธรดอื่น นี่อาจจะดีเมื่อมีการเชื่อมต่อที่เกิดขึ้นพร้อมกันไม่มากนัก แต่เมื่อจำนวนการเชื่อมต่อถึงระดับที่แน่นอนทรัพยากรหน่วยความจำจะถูกใช้โดยเธรดจำนวนมาก ในทางกลับกันการสลับเธรดจำเป็นต้องเปลี่ยนสถานะของโปรเซสเซอร์เช่นค่าของตัวนับโปรแกรมและการลงทะเบียนดังนั้นการสลับระหว่างเธรดจำนวนมากก็เป็นการเสียทรัพยากร
ด้วยการพัฒนาเทคโนโลยีระบบปฏิบัติการที่ทันสมัยให้กลไก I/O ใหม่ที่สามารถหลีกเลี่ยงการสูญเสียทรัพยากรนี้ได้ จากสิ่งนี้ Javanio เกิดและคุณลักษณะตัวแทนของ NIO นั้นไม่ปิดกั้น I/O ทันทีหลังจากนั้นเราพบว่าการใช้ I/O ที่ไม่ปิดกั้นไม่สามารถแก้ปัญหาได้เนื่องจากในโหมดที่ไม่ปิดกั้นวิธีการอ่าน () จะกลับมาทันทีเมื่อข้อมูลไม่ได้อ่าน เราไม่ทราบว่าข้อมูลจะมาถึงเมื่อใดดังนั้นเราจึงสามารถโทรหาวิธีการอ่าน () เพื่อลองอีกครั้ง เห็นได้ชัดว่าเป็นการสูญเสียทรัพยากร CPU จากต่อไปนี้เราสามารถรู้ได้ว่าองค์ประกอบตัวเลือกเกิดมาเพื่อแก้ปัญหานี้
องค์ประกอบหลักของ Javanio
1. ช่อง
แนวคิด
การดำเนินการ I/O ทั้งหมดในชวานิโอขึ้นอยู่กับวัตถุช่องสัญญาณเช่นเดียวกับการดำเนินการสตรีมจะขึ้นอยู่กับวัตถุสตรีมดังนั้นจึงจำเป็นต้องเข้าใจก่อนว่าช่องคืออะไร เนื้อหาต่อไปนี้ถูกตัดตอนมาจากเอกสารของ JDK1.8
Achannel แสดงถึงการเชื่อมต่อภาคผนวกกับ Annexity Suchasahardwaredevice, Afile, Annetworksocket, ส่วนประกอบ oroprogram ที่สามารถดำเนินการใน ORMORY ที่โดดเด่น I/OOPERATIONS, ORWRITING Forexamplereading
จากเนื้อหาข้างต้นเราจะเห็นว่าช่องแสดงถึงการเชื่อมต่อกับเอนทิตีบางอย่างซึ่งอาจเป็นไฟล์ซ็อกเก็ตเครือข่าย ฯลฯ กล่าวอีกนัยหนึ่งช่องคือสะพานที่จัดทำโดย Javanio สำหรับโปรแกรมของเราเพื่อโต้ตอบกับบริการ I/O พื้นฐานของระบบปฏิบัติการ
ช่องเป็นคำอธิบายพื้นฐานและเป็นนามธรรมโต้ตอบกับบริการ I/O ที่แตกต่างกันดำเนินการ I/O ที่แตกต่างกันและใช้งานการใช้งานที่แตกต่างกัน ดังนั้นสิ่งที่เฉพาะเจาะจงรวมถึง filechannel, socketchannel ฯลฯ
ช่องจะคล้ายกับสตรีมเมื่อใช้ สามารถอ่านข้อมูลลงในบัฟเฟอร์หรือเขียนข้อมูลในบัฟเฟอร์ไปยังช่อง
แน่นอนว่ายังมีความแตกต่างซึ่งส่วนใหญ่สะท้อนให้เห็นในสองจุดต่อไปนี้:
ช่องสามารถอ่านและเขียนได้ในขณะที่สตรีมเป็นทางเดียว (แบ่งออกเป็นอินพุตและเอาท์พุทสตรีม)
ช่องมีโหมด I/O ที่ไม่ปิดกั้น
ทำให้สำเร็จ
การใช้งานช่องที่ใช้กันมากที่สุดในชวามีดังนี้และจะเห็นได้ว่าพวกเขาสอดคล้องกับคลาสการทำงาน I/O แบบดั้งเดิมทีละหนึ่ง
FileChannel: อ่านและเขียนไฟล์
DataGramChannel: การสื่อสารเครือข่ายโปรโตคอล UDP
Socketchannel: การสื่อสารเครือข่ายโปรโตคอล TCP
ServersocketChannel: ฟังการเชื่อมต่อ TCP
2. บัฟเฟอร์
บัฟเฟอร์ที่ใช้ใน NIO ไม่ใช่อาร์เรย์ไบต์ที่เรียบง่าย แต่เป็นคลาสบัฟเฟอร์ที่ห่อหุ้ม ผ่าน API ที่มีให้เราสามารถจัดการข้อมูลได้อย่างยืดหยุ่น ลองมาดูกันดีกว่า
สอดคล้องกับประเภทพื้นฐานของ Java NIO ให้ความหลากหลายของบัฟเฟอร์เช่น Bytebuffer, Charbuffer, Intbuffer ฯลฯ ความแตกต่างคือความยาวของหน่วยของบัฟเฟอร์นั้นแตกต่างกันเมื่ออ่านและเขียน (การอ่านและการเขียนในหน่วยของตัวแปรประเภทที่สอดคล้องกัน)
มี 3 ตัวแปรที่สำคัญมากในบัฟเฟอร์ พวกเขาเป็นกุญแจสำคัญในการทำความเข้าใจกลไกการทำงานของบัฟเฟอร์คือ
กำลังการผลิต (ความจุรวม)
ตำแหน่ง (ตำแหน่งปัจจุบันของตัวชี้)
จำกัด (ตำแหน่งขอบเขตการอ่าน/เขียน)
วิธีการทำงานของบัฟเฟอร์นั้นคล้ายกับอาร์เรย์อักขระใน C. ในการเปรียบเทียบความจุคือความยาวทั้งหมดของอาร์เรย์ตำแหน่งคือตัวแปรตัวห้อยสำหรับเราในการอ่าน/เขียนอักขระและขีด จำกัด คือตำแหน่งของอักขระสุดท้าย สถานการณ์ของตัวแปร 3 ตัวที่จุดเริ่มต้นของบัฟเฟอร์มีดังนี้
ในระหว่างกระบวนการอ่าน/เขียนบัฟเฟอร์ตำแหน่งจะเลื่อนไปข้างหลังและขีด จำกัด คือขอบเขตของการเคลื่อนไหวของตำแหน่ง ไม่ยากที่จะจินตนาการว่าเมื่อเขียนไปยังบัฟเฟอร์ควรตั้งค่า จำกัด ให้เป็นขนาดของความจุและเมื่ออ่านบัฟเฟอร์ควรตั้งค่าขีด จำกัด ไว้ที่ตำแหน่งสิ้นสุดที่แท้จริงของข้อมูล (หมายเหตุ: การเขียนข้อมูลบัฟเฟอร์ไปยังช่องคือการดำเนินการอ่านบัฟเฟอร์และการอ่านข้อมูลจากช่องไปยังบัฟเฟอร์คือการดำเนินการเขียนบัฟเฟอร์)
ก่อนที่จะอ่าน/เขียนการดำเนินการบนบัฟเฟอร์เราสามารถเรียกวิธีการเสริมบางอย่างโดยคลาสบัฟเฟอร์เพื่อตั้งค่าตำแหน่งและขีด จำกัด อย่างถูกต้องส่วนใหญ่ดังนี้
FLIP (): ตั้งค่าขีด จำกัด เป็นค่าของตำแหน่งจากนั้นตั้งค่าตำแหน่งเป็น 0. การโทรก่อนอ่านบัฟเฟอร์
REWIND (): เพียงแค่ตั้งตำแหน่ง 0 มันมักจะถูกเรียกก่อนที่จะอ่านข้อมูลบัฟเฟอร์อีกครั้งตัวอย่างเช่นมันจะถูกใช้เมื่ออ่านข้อมูลของบัฟเฟอร์เดียวกันและเขียนลงในหลายช่องทาง
Clear (): กลับไปที่สถานะเริ่มต้นนั่นคือขีด จำกัด เท่ากับความจุตั้งตำแหน่งเป็น 0 โทรบัฟเฟอร์ก่อนเขียน
compact (): ย้ายข้อมูลที่ยังไม่ได้อ่าน (ข้อมูลระหว่างตำแหน่งและขีด จำกัด ) ไปยังจุดเริ่มต้นของบัฟเฟอร์และตั้งตำแหน่งไปยังตำแหน่งถัดไปในตอนท้ายของข้อมูลนี้ ในความเป็นจริงมันเทียบเท่ากับการเขียนชิ้นส่วนข้อมูลดังกล่าวไปยังบัฟเฟอร์อีกครั้ง
จากนั้นดูตัวอย่างใช้ FileChannel เพื่ออ่านและเขียนไฟล์ข้อความและใช้ตัวอย่างนี้เพื่อตรวจสอบลักษณะที่อ่านได้และเขียนได้ของช่องและการใช้บัฟเฟอร์พื้นฐาน (โปรดทราบว่า FileChannel ไม่สามารถตั้งค่าเป็นโหมดที่ไม่ปิดกั้นได้)
FileChannel channel = new randomaccessFile ("test.txt", "rw"). getChannel (); channel.position (channel.size ()); // ย้ายตัวชี้ไฟล์ไปยังจุดสิ้นสุด World!/n ".getBytes (StandardCharSets.UTF_8)); // buffer -> channelbytebuffer.flip (); ในขณะที่ (bytebuffer.hasremaining ()) {channel.write (bytebuffer);} channel.position (0); ตัวถอดรหัส CharsetDecoder = StandardCharSets.UTF_8.newDecoder (); // อ่านข้อมูลทั้งหมด bytebuffer.clear (); ในขณะที่ (channel.read (bytebuffer)! = -1 || bytebuffer.position ()> 0) {bytebuffer.flip (); // decode charbuffer.clear (); decoder.decode (bytebuffer, Charbuffer FALSE); System.out.print (charbuffer.flip (). toString ()); bytebuffer.compact (); // อาจมีข้อมูลที่เหลืออยู่} channel.close ();ในตัวอย่างนี้มีการใช้บัฟเฟอร์สองตัวโดยที่ Bytebuffer เป็นบัฟเฟอร์ข้อมูลสำหรับการอ่านและการเขียนช่องและ Charbuffer ใช้ในการจัดเก็บอักขระที่ถอดรหัส การใช้งานของ Clear () และ Flip () ดังที่ได้กล่าวไว้ข้างต้น ควรสังเกตว่าวิธีการขนาดกะทัดรัด () สุดท้ายคือแม้ว่าขนาดของ Charbuffer นั้นเพียงพอที่จะรองรับข้อมูลที่ถอดรหัส Bytebuffer ได้ แต่สิ่งจำเป็นเช่นกัน นี่เป็นเพราะการเข้ารหัส UTF-8 ของตัวอักษรจีนที่ใช้กันทั่วไปบัญชีสำหรับ 3 ไบต์ดังนั้นจึงมีความน่าจะเป็นสูงที่จะเกิดขึ้นในการตัดทอนกลาง โปรดดูรูปด้านล่าง:
เมื่อตัวถอดรหัสอ่าน 0xE4 ที่ส่วนท้ายของบัฟเฟอร์มันจะไม่สามารถแมปกับ Unicode ได้ พารามิเตอร์ที่สามของวิธีการ DECODE () เท็จใช้เพื่อให้ตัวถอดรหัสปฏิบัติต่อไบต์ที่ไม่สามารถเข้าถึงได้และข้อมูลที่ตามมาเป็นข้อมูลเพิ่มเติม ดังนั้นวิธีการ DECODE () จะหยุดที่นี่และตำแหน่งจะกลับไปที่ตำแหน่ง 0xE4 ด้วยวิธีนี้ไบต์แรกที่ถูกเข้ารหัสด้วยคำว่า "สื่อ" จะถูกทิ้งไว้ในบัฟเฟอร์และจะต้องมีขนาดกะทัดรัดที่ด้านหน้าและเชื่อมต่อกับข้อมูลลำดับที่ถูกต้องและตามมา เกี่ยวกับการเข้ารหัสอักขระคุณสามารถอ้างถึง " คำอธิบายของ ANSI, Unicode, BMP, UTF และแนวคิดการเข้ารหัสอื่น ๆ "
BTW, CharsetDecoder ในตัวอย่างเป็นคุณสมบัติใหม่ของ Javanio ดังนั้นคุณควรค้นพบเล็กน้อย การดำเนินการของ NIO นั้นมุ่งเน้นบัฟเฟอร์ (I/O แบบดั้งเดิมนั้นมุ่งเน้นไปที่สตรีม)
ณ จุดนี้เราได้เรียนรู้เกี่ยวกับการใช้งานพื้นฐานของช่องและบัฟเฟอร์ ต่อไปเราจะพูดคุยเกี่ยวกับองค์ประกอบสำคัญของการปล่อยให้เธรดจัดการหลายช่องทาง
3. ตัวเลือก
ตัวเลือกคืออะไร
ตัวเลือกเป็นองค์ประกอบพิเศษที่ใช้ในการรวบรวมสถานะ (หรือเหตุการณ์) ของแต่ละช่อง ก่อนอื่นเราลงทะเบียนช่องไปยังตัวเลือกและตั้งค่ากิจกรรมที่เราใส่ใจจากนั้นเราสามารถรอให้กิจกรรมเกิดขึ้นได้อย่างเงียบ ๆ โดยเรียกวิธีการเลือก ()
ช่องมี 4 เหตุการณ์ต่อไปนี้เพื่อให้เราฟัง:
ยอมรับ: มีการเชื่อมต่อที่ยอมรับได้
เชื่อมต่อ: เชื่อมต่อสำเร็จ
อ่าน: มีข้อมูลที่ต้องอ่าน
เขียน: คุณสามารถเขียนข้อมูลได้
ทำไมต้องใช้ตัวเลือก
ดังที่ได้กล่าวไว้ข้างต้นหากคุณใช้การบล็อก I/O คุณจะต้องมีมัลติเธรด (เสียหน่วยความจำ) และหากคุณใช้ I/O ที่ไม่ปิดกั้นคุณต้องลองอีกครั้งอย่างต่อเนื่อง (การบริโภค CPU) การเกิดขึ้นของตัวเลือกช่วยแก้ปัญหาที่น่าอับอายนี้ ในโหมดที่ไม่ปิดกั้นผ่านตัวเลือกเธรดของเราใช้งานได้เฉพาะกับช่องทางพร้อมและไม่จำเป็นต้องลองอย่างสุ่มสี่สุ่มห้า ตัวอย่างเช่นเมื่อไม่มีข้อมูลในทุกช่องสัญญาณจะไม่มีเหตุการณ์อ่านเกิดขึ้นและเธรดของเราจะถูกระงับที่วิธีการเลือก () ดังนั้นจึงให้ทรัพยากร CPU
วิธีใช้
ดังที่แสดงด้านล่างสร้างตัวเลือกและลงทะเบียนช่อง
หมายเหตุ: ในการลงทะเบียนช่องเป็นตัวเลือกคุณต้องตั้งค่าช่องเป็นโหมดที่ไม่ปิดกั้นมิฉะนั้นจะมีการโยนข้อยกเว้น
ตัวเลือกตัวเลือก = selector.open (); channel.configureblocking (false); selectionKey key = channel.register (ตัวเลือก, selectionKey.op_read);
พารามิเตอร์ที่สองของวิธีการลงทะเบียน () เรียกว่า "ชุดดอกเบี้ย" ซึ่งเป็นชุดเหตุการณ์ที่คุณกังวล หากคุณใส่ใจเกี่ยวกับหลาย ๆ เหตุการณ์ให้แยกพวกเขาด้วย "บิทัลหรือผู้ดำเนินการ" เช่น
selectionKey.op_read | selectionKey.op_write
วิธีการเขียนนี้ไม่คุ้นเคยกับมัน มันเล่นในภาษาการเขียนโปรแกรมที่สนับสนุนการดำเนินการบิต การใช้ตัวแปรจำนวนเต็มสามารถระบุหลายสถานะ เป็นอย่างไรบ้าง? มันง่ายมาก ตัวอย่างเช่นก่อนกำหนดค่าคงที่บางส่วนและค่าของพวกเขา (ไบนารี) มีดังนี้
จะพบได้ว่าบิตที่มีค่าของพวกเขาอยู่ที่ 1 นั้นทั้งหมดถูกเซดังนั้นค่าที่ได้รับหลังจากดำเนินการ bitwise หรือการคำนวณบนพวกเขาไม่มีความคลุมเครือและพวกเขาสามารถอนุมานได้ผกผันซึ่งตัวแปรถูกคำนวณจาก วิธีการตัดสินใช่มันคือ "บิตและ" การดำเนินการ ตัวอย่างเช่นขณะนี้มีค่าตัวแปรที่ตั้งค่าสถานะของ 0011 เราจำเป็นต้องพิจารณาว่าค่าของ "0011 & op_read" คือ 1 หรือ 0 เพื่อตรวจสอบว่าชุดมีสถานะ op_read หรือไม่
จากนั้นโปรดทราบว่าเมธอด register () ส่งคืนวัตถุ SelectionKey ซึ่งมีข้อมูลสำหรับการลงทะเบียนนี้และเรายังสามารถแก้ไขข้อมูลการลงทะเบียนผ่านได้ จากตัวอย่างที่สมบูรณ์ด้านล่างเราจะเห็นว่าหลังจากเลือก () เรายังได้รับช่องทางพร้อมสถานะพร้อมด้วยการได้รับคอลเลกชันของ SelectionKeys
ตัวอย่างที่สมบูรณ์
แนวคิดและสิ่งทฤษฎีได้รับการอธิบาย (จริง ๆ แล้วหลังจากเขียนที่นี่ฉันพบว่าฉันไม่ได้เขียนอะไรมากซึ่งน่าอาย (⊙ˍ⊙)) มาดูตัวอย่างที่สมบูรณ์
ตัวอย่างนี้ใช้ Javanio เพื่อใช้เซิร์ฟเวอร์แบบเธรดเดี่ยว ฟังก์ชั่นง่ายมาก มันฟังการเชื่อมต่อไคลเอนต์ เมื่อมีการสร้างการเชื่อมต่อจะอ่านข้อความของลูกค้าและตอบกลับข้อความถึงลูกค้า
ควรสังเกตว่าฉันใช้ตัวละคร '/0' (ไบต์ที่มีค่า 0) เพื่อระบุจุดสิ้นสุดของข้อความ
เซิร์ฟเวอร์เธรดเดี่ยว
คลาสสาธารณะ nioserver {โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่น ioexception {// สร้างตัวเลือกตัวเลือก selectelector = selector.open (); // เริ่มต้นการเชื่อมต่อการเชื่อมต่อการเชื่อมต่อ TCP listenchannel.bind (ใหม่ inetSocketAddress (9999)); listenchannel.configureblocking (เท็จ); // ลงทะเบียนไปยังตัวเลือก (ฟังเหตุการณ์ที่ยอมรับ) listennel.register (ตัวเลือก, selectionKey.op_accept); // สร้างบัฟเฟอร์บัฟเฟอร์บัฟเฟอร์บัฟเฟอร์ = byTebuffer.Allocate (100); ในขณะที่ (จริง) {selector.select (); // บล็อกจนกระทั่งเหตุการณ์ถูกฟังว่าเกิดขึ้น iterator <SelectionKey> keyIter = selector.selectedKeys () Iterator (); // เข้าถึงเหตุการณ์ช่องที่เลือกผ่านตัววนซ้ำในขณะที่ (keyiter.hasnext () socketchannel channel = ((serversocketChannel) key.channel ()). ยอมรับ (); channel.configureblocking (เท็จ); channel.register (ตัวเลือก, selectionkey.op_read); system.out.println ("การเชื่อมต่อที่มี [" buffer.clear (); // อ่านไปที่จุดสิ้นสุดของสตรีมแสดงให้เห็นว่าการเชื่อมต่อ TCP ถูกตัดการเชื่อมต่อ // ดังนั้นจึงจำเป็นต้องปิดช่องหรือยกเลิกการฟังเหตุการณ์การอ่าน // อย่างอื่นมันจะวนลูปอย่างไม่สิ้นสุดถ้า ((socketchannel) key.channel () byte buffer.flip (); ในขณะที่ (buffer.hasremaining ()) {byte b = buffer.get (); ถ้า (b == 0) {// // /0system.out.out.println () ที่ส่วนท้ายของข้อความไคลเอนต์; {((socketchannel) key.channel ()). เขียน (บัฟเฟอร์);}} else {system.out.print ((char) b);}}} // สำหรับเหตุการณ์ที่ได้รับการประมวลผลคุณต้องลบ keyiter.remove ();}}}}}}ลูกค้า
ไคลเอนต์นี้ใช้อย่างหมดจดสำหรับการทดสอบ เพื่อที่จะทำให้มันยากน้อยลงมันใช้วิธีการเขียนแบบดั้งเดิมและรหัสสั้นมาก
หากคุณต้องการการทดสอบอย่างเข้มงวดมากขึ้นคุณควรเรียกใช้ลูกค้าจำนวนมากพร้อมกันเพื่อนับเวลาตอบสนองของเซิร์ฟเวอร์และไม่ส่งข้อมูลทันทีหลังจากการเชื่อมต่อถูกสร้างขึ้นเพื่อให้ได้รับประโยชน์อย่างเต็มที่กับข้อดีของ I/O ที่ไม่ปิดกั้นบนเซิร์ฟเวอร์
ไคลเอนต์ระดับสาธารณะ {โมฆะคงที่สาธารณะหลัก (สตริง [] args) โยนข้อยกเว้น {ซ็อกเก็ตซ็อกเก็ต = ซ็อกเก็ตใหม่ ("localhost", 9999); inputstream คือ = socket.getInputStream (); outputstream os = socket.getOutputStream (); // ส่งข้อมูลไปยังเซิร์ฟเวอร์ B; ในขณะที่ ((b = is.read ())! = 0) {system.out.print ((char) b);} system.out.println (); socket.close ();}}}สรุป
ข้างต้นคือทั้งหมดที่เกี่ยวกับความเข้าใจอย่างรวดเร็วเกี่ยวกับองค์ประกอบหลักของ NIO ใน Java ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงเนื้อหาที่เกี่ยวข้องอื่น ๆ ของเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!