ชีวภาพนั่นคือการปิดกั้น IO ในระหว่างกระบวนการสื่อสารข้อความที่ใช้ซ็อกเก็ตซ็อกเก็ตเซิร์ฟเวอร์ให้บริการด้านนอกและไคลเอ็นต์ซ็อกเก็ตสามารถสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ซ็อกเก็ตจากนั้นส่งข้อมูลคำขอจากนั้นรอให้เซิร์ฟเวอร์ซ็อกเก็ตเซิร์ฟเวอร์ประมวลผลและส่งคืนผลการประมวลผล (การตอบสนอง)
จากการสื่อสารทางชีวภาพเซิร์ฟเวอร์ซ็อกเก็ตจะบล็อกนั่นคือทุกครั้งที่การเชื่อมต่อซ็อกเก็ตกับไคลเอนต์ได้รับการยอมรับในระหว่างกระบวนการฟังคำขอจะต้องดำเนินการและในเวลานี้ไคลเอนต์ที่เชื่อมต่ออื่น ๆ สามารถบล็อกและรอได้เท่านั้น จะเห็นได้ว่าความสามารถในการประมวลผลของเซิร์ฟเวอร์ซ็อกเก็ตในโหมดนี้มี จำกัด มากและไคลเอนต์สามารถรอได้จนกว่าเซิร์ฟเวอร์จะไม่ได้ใช้งานและจัดการคำขอ
การใช้งานการสื่อสารทางชีวภาพ
ต่อไปนี้ขึ้นอยู่กับโมเดลชีวภาพเพื่อใช้ตรรกะของเซิร์ฟเวอร์ซ็อกเก็ตอย่างง่ายที่สื่อสารกับไคลเอนต์ซ็อกเก็ตและมีความเข้าใจในการรับรู้ของวิธีการสื่อสารนี้ ตรรกะเฉพาะอธิบายดังนี้:
1. ไคลเอ็นต์ซ็อกเก็ตเชื่อมต่อกับซ็อกเก็ตเซิร์ฟเวอร์และส่งข้อมูล "ฉันเป็นไคลเอนต์ N";
2. เซิร์ฟเวอร์ซ็อกเก็ตฟังพอร์ตบริการและรับข้อมูลคำขอไคลเอนต์ หากข้อมูลคำขอเริ่มต้นด้วย "ฉันเป็นไคลเอนต์" จะตอบสนองต่อไคลเอนต์ "ฉันเป็นเซิร์ฟเวอร์และคุณเป็นไคลเอนต์ Nth";
การใช้งาน Socket Server มีดังนี้:
แพ็คเกจ org.shirdrn.java.Communications.bio; นำเข้า java.io.ioException; นำเข้า Java.io.InputStream; นำเข้า Java.io.OutputStream; นำเข้า java.net.serversocket; นำเข้า java.net.socket; / *** อิงเซิร์ฟเวอร์ซ็อกเก็ตบน Bio** @author shieldrn*/ คลาสสาธารณะ SimpleBiotCpserver ขยายเธรด {/ ** หมายเลขพอร์ตบริการ*/ พอร์ต int ส่วนตัว = 8888; / ** กำหนดหมายเลข*/ ส่วนตัวคงที่ int ให้กับลำดับไคลเอนต์ = 0; สาธารณะ simplebiotcpserver (พอร์ต int) {this.port = พอร์ต; } @Override โมฆะสาธารณะเรียกใช้ () {ซ็อกเก็ตซ็อกเก็ต = null; ลอง {Serversocket Serversocket = ใหม่ Serversocket (this.port); ในขณะที่ (จริง) {socket = serversocket.accept (); // ฟัง this.handlemessage (ซ็อกเก็ต); // handlemessage (ซ็อกเก็ต); // จัดการคำขอไคลเอนต์ที่เชื่อมต่อ}} catch (ioexception e) {e.printstacktrace (); }} / ** * จัดการการเชื่อมต่อซ็อกเก็ตไคลเอนต์ * @param ซ็อกเก็ตซ็อกเก็ตไคลเอนต์ * @throws ioexception * / โมฆะส่วนตัว handlemessage (ซ็อกเก็ตซ็อกเก็ต) พ่น IOException {inputstream ใน = socket.getInputStream (); // สตรีม: ไคลเอนต์-> เซิร์ฟเวอร์ (อ่าน) outputStream out = socket.getOutputStream (); // สตรีม: เซิร์ฟเวอร์-> ไคลเอนต์ (เขียน) int รับ bytes; ไบต์ [] รับบัฟเฟอร์ = ไบต์ใหม่ [128]; String ClientMessage = ""; if ((รับ byBytes = in.read (รับ buffer))! =-1) {clientMessage = สตริงใหม่ (รับ buffer, 0, รับ bybytes); if (clientMessage.startswith ("ฉันเป็นไคลเอนต์")) {String ServerResponSewords = "ฉันเป็นเซิร์ฟเวอร์และคุณคือ" + (++ ลำดับ) + "ไคลเอนต์ th"; out.write (ServerResponSewords.getBytes ()); }} out.flush (); System.out.println ("เซิร์ฟเวอร์: รับ clientMessage->" + clientMessage); } โมฆะคงที่สาธารณะหลัก (สตริง [] args) {simplebiotcpserver server = new simplebiotcpserver (1983); Server.start (); - การใช้งานข้างต้นไม่ได้ทำการประมวลผลข้อยกเว้นที่ซับซ้อน
การใช้งานซ็อกเก็ตไคลเอนต์มีดังนี้:
แพ็คเกจ org.shirdrn.java.Communications.bio; นำเข้า java.io.ioException; นำเข้า Java.io.InputStream; นำเข้า Java.io.OutputStream; นำเข้า java.net.socket; นำเข้า java.net.unknownhostexception; นำเข้า java.util.date; / ** * ซ็อกเก็ตไคลเอ็นต์ตาม Bio * * @author shieldrn */ คลาสสาธารณะ simplebiotcplient {สตริงส่วนตัว ipaddress; พอร์ต int ส่วนตัว; INT คงที่ส่วนตัว pos = 0; Public SimpleBiotCPClient () {} สาธารณะ SimpleBiotCpClient (String iPaddress, พอร์ต int) {this.ipaddress = iPaddress; this.port = พอร์ต; } / *** เชื่อมต่อกับซ็อกเก็ตเซิร์ฟเวอร์และจำลองการส่งข้อมูลคำขอ* @param ข้อมูลคำขอข้อมูล* / โมฆะสาธารณะส่ง (byte [] ข้อมูล) {ซ็อกเก็ตซ็อกเก็ต = null; outputstream out = null; inputStream ใน = null; ลอง {socket = ซ็อกเก็ตใหม่ (this.ipaddress, this.port); // เชื่อมต่อ // ส่งคำขอ = socket.getOutputStream (); out.write (ข้อมูล); out.flush (); // รับการตอบกลับใน = socket.getInputStream (); int totalBytes = 0; int รับ bytes = 0; ไบต์ [] รับบัฟเฟอร์ = ไบต์ใหม่ [128]; if ((รับ byBytes = in.read (รับ buffer))! =-1) {totalBytes += รับ byBytes; } string serverMessage = สตริงใหม่ (รับ Buffer, 0, รับ bytes); System.out.println ("ไคลเอนต์: รับ ServerMessage->" + ServerMessage); } catch (unknownhostexception e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } catch (exception e) {e.printstacktrace (); } ในที่สุด {ลอง {// ส่งคำขอและรับการตอบกลับการสื่อสารเสร็จสมบูรณ์ปิดการเชื่อมต่อออก. close (); in.close (); Socket.close (); } catch (ioexception e) {e.printstacktrace (); }}} โมฆะคงที่สาธารณะหลัก (สตริง [] args) {int n = 1; StringBuffer data = new StringBuffer (); วันที่เริ่มต้น = วันที่ใหม่ (); สำหรับ (int i = 0; i <n; i ++) {data.delete (0, data.length ()); data.append ("ฉันเป็นลูกค้า") .append (++ pos) .append ("."); simplebiotcplient client = new simplebiotcplient ("localhost", 1983); client.send (data.toString (). getBytes ()); } วันที่สิ้นสุด = วันที่ใหม่ (); ค่าใช้จ่ายยาว = end.getTime () - start.getTime (); System.out.println (n + "คำขอค่าใช้จ่าย" + cost + "ms."); - ก่อนอื่นให้เริ่มกระบวนการ SimpleBiotCpserver จากนั้นเรียกใช้ Socket Client SimpleBiotCPClient จะเห็นได้ว่าเซิร์ฟเวอร์ได้รับข้อมูลคำขอแล้วตอบกลับไปยังไคลเอนต์และไคลเอนต์จะได้รับข้อมูลการตอบกลับจากเซิร์ฟเวอร์
ในการใช้งานข้างต้นทั้งไคลเอ็นต์ซ็อกเก็ตและเซิร์ฟเวอร์จะถูกเขียนและอ่านในครั้งเดียว ในความเป็นจริงหากจำนวนข้อมูลมีขนาดใหญ่เป็นพิเศษในระหว่างการสื่อสารแต่ละครั้งเซิร์ฟเวอร์ไม่สามารถยอมรับได้ มันสามารถวนซ้ำเพื่ออ่านและประมวลผลเมื่อกำหนดจำนวนไบต์ข้อมูลที่ลูกค้าร้องขอ
นอกจากนี้หากสตรีมที่กล่าวถึงข้างต้นไม่ได้ถูกห่อหุ้มจะมีการสูญเสียประสิทธิภาพในทางปฏิบัติเช่นการไร้ความสามารถในการบัฟเฟอร์ ฯลฯ
สำหรับซ็อกเก็ตเซิร์ฟเวอร์ที่ได้รับข้อมูลจะสะดวกกว่ามากหากข้อมูลไบต์ที่อ่านจากหลายลูปสามารถเก็บไว้ในบัฟเฟอร์ไบต์ที่มีความยาวตัวแปร อย่างไรก็ตามการใช้ ByTeArrayOutputStream ตัวอย่างเช่น:
ByTeArrayOutputStream data = ใหม่ byteArrayOutputStream (); data.write (รับ Buffer, TotalBytes, TotalBytes + รับ BYTES);
การทดสอบการสื่อสารทางชีวภาพ
การทดสอบต่อไปนี้ประสิทธิภาพของการประมวลผลเซิร์ฟเวอร์ซ็อกเก็ตในสถานการณ์ที่มีคำขอจำนวนมาก
วิธีแรก: เริ่มต้น 5000 ซ็อกเก็ตไคลเอนต์ผ่าน A for Loop และส่งคำขอ รหัสมีดังนี้:
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {int n = 5000; StringBuffer data = new StringBuffer (); วันที่เริ่มต้น = วันที่ใหม่ (); สำหรับ (int i = 0; i <n; i ++) {data.delete (0, data.length ()); data.append ("ฉันเป็นลูกค้า") .append (++ pos) .append ("."); simplebiotcplient client = new simplebiotcplient ("localhost", 1983); client.send (data.toString (). getBytes ()); } วันที่สิ้นสุด = วันที่ใหม่ (); ค่าใช้จ่ายยาว = end.getTime () - start.getTime (); System.out.println (n + "คำขอค่าใช้จ่าย" + cost + "ms."); - หลังจากการทดสอบจะใช้เวลาประมาณ 9864ms ซึ่งประมาณ 10 วินาที
วิธีที่สอง: เริ่มเธรดไคลเอนต์อิสระ 5,000 เธรดและคำขอในเวลาเดียวกันและเซิร์ฟเวอร์นับ:
แพ็คเกจ org.shirdrn.java.Communications.bio; นำเข้า java.io.ioException; นำเข้า Java.io.InputStream; นำเข้า Java.io.OutputStream; นำเข้า java.net.serversocket; นำเข้า java.net.socket; นำเข้า java.net.unknownhostexception; นำเข้า java.util.date; / ** * การทดสอบการสื่อสารของซ็อกเก็ตตาม Bio * * @author shieldrn */ คลาสสาธารณะ SimpleBiotCptest {Static int threadCount = 5000; / *** กระบวนการเซิร์ฟเวอร์ซ็อกเก็ตตาม Bio** @author shieldrn*/ socketserver คลาสคงที่ขยายเธรด {/ ** หมายเลขพอร์ตบริการ*/ พอร์ต int ส่วนตัว = 8888; / ** กำหนดหมายเลขให้กับไคลเอนต์*/ ลำดับ int คงที่ส่วนตัว = 0; Socketserver สาธารณะ (พอร์ต int) {this.port = พอร์ต; } @Override โมฆะสาธารณะเรียกใช้ () {ซ็อกเก็ตซ็อกเก็ต = null; int counter = 0; ลอง {Serversocket Serversocket = ใหม่ Serversocket (this.port); ธงบูลีน = เท็จ; วันที่เริ่มต้น = null; ในขณะที่ (จริง) {socket = serversocket.accept (); // ฟัง // เวลาเริ่มต้นถ้า (! ธง) {start = new Date (); ธง = จริง; } this.handlemessage (ซ็อกเก็ต); // จัดการคำขอไคลเอนต์ที่เชื่อมต่อถ้า (++ counter == threadCount) {วันที่สิ้นสุด = วันที่ใหม่ (); long lint = end.getTime () - start.getTime (); System.out.println (ThreadCount + "คำขอค่าใช้จ่าย" + Last + "MS."); }}}} catch (ioexception e) {e.printstacktrace (); }} / ** * จัดการการเชื่อมต่อซ็อกเก็ตไคลเอนต์ * @param ซ็อกเก็ตซ็อกเก็ตไคลเอนต์ * @throws ioexception * / โมฆะส่วนตัว handlemessage (ซ็อกเก็ตซ็อกเก็ต) พ่น IOException {inputstream ใน = socket.getInputStream (); // สตรีม: ไคลเอนต์-> เซิร์ฟเวอร์ (อ่าน) outputStream out = socket.getOutputStream (); // สตรีม: เซิร์ฟเวอร์-> ไคลเอนต์ (เขียน) int รับ bytes; ไบต์ [] รับบัฟเฟอร์ = ไบต์ใหม่ [128]; String ClientMessage = ""; if ((รับ byBytes = in.read (รับ buffer))! =-1) {clientMessage = สตริงใหม่ (รับ buffer, 0, รับ bybytes); if (clientMessage.startswith ("ฉันเป็นไคลเอนต์")) {String ServerResponSewords = "ฉันเป็นเซิร์ฟเวอร์และคุณคือ" + (++ ลำดับ) + "ไคลเอนต์ th"; out.write (ServerResponSewords.getBytes ()); }} out.flush (); System.out.println ("เซิร์ฟเวอร์: รับ clientMessage->" + clientMessage); }} / ** * เธรดไคลเอ็นต์ซ็อกเก็ตตาม Bio * * @author shieldrn * / socketclient คลาสคงที่ใช้งาน {สตริงส่วนตัว ipaddress; พอร์ต int ส่วนตัว; / ** ข้อมูลคำขอที่จะส่ง*/ ข้อมูลสตริงส่วนตัว; SocketClient สาธารณะ (String iPaddress, int พอร์ต) {this.ipaddress = iPaddress; this.port = พอร์ต; } @Override โมฆะสาธารณะ Run () {this.send (); } / *** เชื่อมต่อกับซ็อกเก็ตเซิร์ฟเวอร์และจำลองการส่งข้อมูลคำขอ* / โมฆะสาธารณะส่ง () {ซ็อกเก็ตซ็อกเก็ต = null; outputstream out = null; inputStream ใน = null; ลอง {socket = ซ็อกเก็ตใหม่ (this.ipaddress, this.port); // เชื่อมต่อ // ส่งคำขอ = socket.getOutputStream (); out.write (data.getBytes ()); out.flush (); // รับการตอบกลับใน = socket.getInputStream (); int totalBytes = 0; int รับ bytes = 0; ไบต์ [] รับบัฟเฟอร์ = ไบต์ใหม่ [128]; if ((รับ byBytes = in.read (รับ buffer))! =-1) {totalBytes += รับ byBytes; } string serverMessage = สตริงใหม่ (รับ Buffer, 0, รับ bytes); System.out.println ("ไคลเอนต์: รับ ServerMessage->" + ServerMessage); } catch (unknownhostexception e) {e.printstacktrace (); } catch (ioexception e) {e.printstacktrace (); } catch (exception e) {e.printstacktrace (); } ในที่สุด {ลอง {// ส่งคำขอและรับการตอบกลับการสื่อสารเสร็จสมบูรณ์ปิดการเชื่อมต่อออก. close (); in.close (); Socket.close (); } catch (ioexception e) {e.printstacktrace (); }}} โมฆะสาธารณะ setData (ข้อมูลสตริง) {this.data = data; }} โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่นข้อยกเว้น {SocketServer Server = SocketServer ใหม่ (1983); Server.start (); Thread.sleep (3000); สำหรับ (int i = 0; i <threadcount; i ++) {socketClient client = socketClient ใหม่ ("localhost", 1983); client.setData ("ฉันเป็นไคลเอนต์" + (i + 1) + "."); เธรดใหม่ (ไคลเอนต์). start (); Thread.sleep (0, 1); -หลังจากการทดสอบจะใช้เวลาประมาณ 7110ms ซึ่งประมาณ 7s และไม่มีการปรับปรุงครั้งใหญ่
การปรับปรุงการสื่อสารทางชีวภาพ
จากการทดสอบข้างต้นเราสามารถพบได้ว่าเมื่อเซิร์ฟเวอร์ซ็อกเก็ตประมวลผลคำขอจากไคลเอนต์การบล็อกเกิดขึ้นซึ่งส่งผลกระทบอย่างรุนแรงต่อประสิทธิภาพของการประมวลผลคำขอพร้อมกัน ในความเป็นจริงภายในขอบเขตของความสามารถในการเชื่อมต่อของซ็อกเก็ตเซิร์ฟเวอร์คำขอที่ได้รับสามารถเป็นอิสระเพื่อแก้ปัญหาข้างต้นโดยการประมวลผลคำขอโดยคำขอหนึ่งครั้งและหนึ่งเธรด ด้วยวิธีนี้ฝั่งเซิร์ฟเวอร์มีเธรดการประมวลผลหลายรายการที่สอดคล้องกับคำขอหลายรายการของไคลเอ็นต์และประสิทธิภาพการประมวลผลได้รับการปรับปรุงในระดับหนึ่ง
ด้านล่างรับคำขอผ่านเธรดเดียวจากนั้นมอบหมายพูลเธรดเพื่อดำเนินการตามคำขอการประมวลผลแบบหลายเธรดที่เกิดขึ้นพร้อมกัน:
/ *** กระบวนการเซิร์ฟเวอร์ซ็อกเก็ตตาม Bio** @author shieldrn*/ socketserver คลาสคงที่ขยายเธรด {/ ** หมายเลขพอร์ตบริการ*/ พอร์ต int ส่วนตัว = 8888; / ** กำหนดหมายเลขให้กับไคลเอนต์*/ ลำดับ int คงที่ส่วนตัว = 0; / ** พูลเธรดสำหรับการประมวลผลคำขอไคลเอนต์*/ Private ExecutorService Pool; Socketserver สาธารณะ (พอร์ต int, int poolsize) {this.port = พอร์ต; this.pool = executors.newFixedThreadPool (poolsize); } @Override โมฆะสาธารณะเรียกใช้ () {ซ็อกเก็ตซ็อกเก็ต = null; int counter = 0; ลอง {Serversocket Serversocket = ใหม่ Serversocket (this.port); ธงบูลีน = เท็จ; วันที่เริ่มต้น = null; ในขณะที่ (จริง) {socket = serversocket.accept (); // ฟัง // เวลาเริ่มต้นหากคำขอมาหาก (! Flag) {start = new Date (); ธง = จริง; } // ใส่คำขอไคลเอ็นต์ลงในพูลเธรดเพื่อประมวลผลพูล Execute (New RequestHandler (ซ็อกเก็ต)); if (++ counter == threadCount) {วันที่สิ้นสุด = วันที่ใหม่ (); long lint = end.getTime () - start.getTime (); System.out.println (ThreadCount + "คำขอค่าใช้จ่าย" + Last + "MS."); }}} catch (ioexception e) {e.printstacktrace (); }} / ** * การร้องขอไคลเอ็นต์การประมวลผลเธรดคลาส * * @author shieldrn * / คลาส requesthandler ใช้การใช้งาน runnable {ซ็อกเก็ตซ็อกเก็ตส่วนตัว; Public RequestHandler (ซ็อกเก็ตซ็อกเก็ต) {this.socket = ซ็อกเก็ต; } @Override โมฆะสาธารณะเรียกใช้ () {ลอง {inputStream ใน = socket.getInputStream (); // สตรีม: ไคลเอนต์-> เซิร์ฟเวอร์ (อ่าน) outputStream out = socket.getOutputStream (); // สตรีม: เซิร์ฟเวอร์-> ไคลเอนต์ (เขียน) int รับ bytes; ไบต์ [] รับบัฟเฟอร์ = ไบต์ใหม่ [128]; String ClientMessage = ""; if ((รับ byBytes = in.read (รับ buffer))! =-1) {clientMessage = สตริงใหม่ (รับ buffer, 0, รับ bybytes); if (clientMessage.startswith ("ฉันเป็นไคลเอนต์")) {String ServerResponSewords = "ฉันเป็นเซิร์ฟเวอร์และคุณคือ" + (++ ลำดับ) + "ไคลเอนต์ th"; out.write (ServerResponSewords.getBytes ()); }} out.flush (); System.out.println ("เซิร์ฟเวอร์: รับ clientMessage->" + clientMessage); } catch (ioexception e) {e.printstacktrace (); -จะเห็นได้ว่าวิธีการที่ได้รับการปรับปรุงนี้ช่วยเพิ่มการเกิดขึ้นพร้อมกันของคำขอการประมวลผลเซิร์ฟเวอร์ แต่แต่ละคำขอจะต้องดำเนินการโดยเธรด คำขอจำนวนมากทำให้เซิร์ฟเวอร์เริ่มกระบวนการจำนวนมากสำหรับการประมวลผลซึ่งค่อนข้างใช้ทรัพยากรเซิร์ฟเวอร์
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น