السيرة الذاتية ، وهذا هو ، منع IO. أثناء عملية اتصال الرسائل المستندة إلى المقبس ، يوفر Socket Server الخدمات إلى الخارج ، ويمكن لعميل المقبس إنشاء اتصال بخادم المقبس ، ثم إرسال بيانات الطلب ، ثم انتظر خادم المقبس للمعالجة ، وإرجاع نتيجة المعالجة (استجابة).
استنادًا إلى الاتصال الحيوي ، سيتم حظر خادم المقبس ، أي في كل مرة يتم فيها قبول اتصال المقبس مع العميل أثناء عملية الاستماع ، يجب معالجة الطلب ، وفي هذا الوقت ، يمكن للعملاء الآخرين المتصلين فقط حظر والانتظار. يمكن ملاحظة أن إمكانية المعالجة لخادم المقبس في هذا الوضع محدودة للغاية ، ويمكن للعميل الانتظار فقط حتى يكون الخادم خاملاً ويتعامل مع الطلب.
تنفيذ الاتصالات الحيوية
يعتمد ما يلي على النموذج الحيوي لتنفيذ منطق خادم المقبس البسيط الذي يتواصل مع عميل المقبس ، ولديه فهم إدراكي لطريقة الاتصال هذه. يوصف المنطق المحدد على النحو التالي:
1. يتصل عميل المقبس بخادم المقبس ويرسل البيانات "أنا العميل N." ؛
2. يستمع خادم المقبس إلى منفذ الخدمة ويتلقى بيانات طلب العميل. إذا بدأت بيانات الطلب بـ "أنا العميل" ، فإنها تستجيب للعميل "أنا الخادم ، وأنت العميل nth." ؛
تطبيق خادم المقبس هو كما يلي:
حزمة org.shirdrn.java.communications.bio ؛ استيراد java.io.ioException ؛ استيراد java.io.inputstream ؛ استيراد java.io.outputStream ؛ استيراد java.net.serversocket ؛ استيراد java.net.socket ؛ / *** Socket Server على Bio** Author Shieldrn*/ فئة عامة SimpleBiotCpserver يمتد Thread {/ ** رقم منفذ الخدمة*/ Private Int Port = 8888 ؛ / ** تعيين رقم*/ int ثابت خاص لتسلسل العميل = 0 ؛ public SimpleBiotCpserver (int port) {this.port = port ؛ } Override public void run () {Socket Socket = null ؛ جرب {serversocket severocket = new servers (this.port) ؛ بينما (صواب) {socket = serversOcket.accept () ؛ // استمع إلى this.handlemessage (المقبس) ؛ // HandleMessage (Socket) ؛ // التعامل مع طلب عميل متصل}} catch (ioException e) {E.PrintStackTrace () ؛ }} / ** * تعامل مع اتصال مقبس العميل * Param Socket Client Socket * Throws IOException * / private void handlemessage (Socket Socket) يلقي iOexception {inputStream في = socket.getInputStream () ؛ // دفق: client-> server (read) outputStream out = socket.getOutputStream () ؛ // دفق: server-> client (write) intbytes ؛ byte [] receptbuffer = new byte [128] ؛ سلسلة clientMessage = "" ؛ if ((receberBytes = in.Read (recebuffer))! =-1) {clientMessage = new string (recebuffer ، 0 ، receptbytes) ؛ if (clientMessage.startswith ("أنا العميل")) {String serverResponseWords = "أنا الخادم ، وأنت" + (++ تسلسل) + "العميل TH." ؛ out.write (serverResponsewords.getBytes ()) ؛ }} out.flush () ؛ System.out.println ("الخادم: يتلقى clientMessage->" + clientMessage) ؛ } main static void main (string [] 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 ؛ / ** * عميل Socket استنادًا إلى Bio * * Author Shieldrn */ public class simplebiotcpclient {private string ipaddress ؛ منفذ الباحث الخاص ؛ int static int static الخاص = 0 ؛ public simplebiotcpclient () {} public simplebiotcpclient (سلسلة ipaddress ، int port) {this.ipaddress = ipaddress ؛ this.port = port ؛ } / *** قم بالاتصال بخادم المقبس ومحاكاة بيانات إرسال بيانات الطلب* param data request data* / public void send (byte [] data) {Socket Socket = null ؛ OutputStream Out = null ؛ inputStream في = null ؛ Try {Socket = New Socket (this.ipaddress ، this.port) ؛ // connect // إرسال طلب out = socket.getOutputStream () ؛ out.write (البيانات) ؛ out.flush () ؛ // استقبال استجابة في = socket.getInputStream () ؛ int totalBytes = 0 ؛ int recebytes = 0 ؛ byte [] receptbuffer = new byte [128] ؛ if ((receberBytes = in.Read (recebuffer))! =-1) {totalBytes += receberbytes ؛ } string serverMessage = new string (recebuffer ، 0 ، receptbytes) ؛ system.out.println ("العميل: يستقبل serverMessage->" + serverMessage) ؛ } catch (unknownHostException e) {E.PrintStackTrace () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ } أخيرًا {try {// أرسل طلبًا واستلام استجابة ، يتم الانتهاء من الاتصال ، وأغلق الاتصال Out.Close () ؛ in.close () ؛ socket.close () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}} public static void main (string [] args) {int n = 1 ؛ DataBuffer Data = new StringBuffer () ؛ تاريخ البدء = تاريخ جديد () ؛ لـ (int i = 0 ؛ i <n ؛ i ++) {data.delete (0 ، data.length ()) ؛ data.append ("أنا العميل") .append (++ pos) .append (".") ؛ CompleBiotCpclient Client = new SimpleBiotCpclient ("LocalHost" ، 1983) ؛ client.send (data.toString (). getBytes ()) ؛ } نهاية التاريخ = تاريخ جديد () ؛ تكلفة طويلة = end.getTime () - start.getTime () ؛ System.out.println (N + "طلبات التكلفة" + التكلفة + "MS.") ؛ }} قم أولاً ببدء عملية Socket Server SimpleBiotCpserver ، ثم قم بتشغيل Socket Client SimpleBiotCpclient. يمكن ملاحظة أن الخادم يتلقى بيانات الطلب ثم يستجيب للعميل ، ويتلقى العميل بيانات الاستجابة من الخادم.
في التنفيذ أعلاه ، يتم كتابة كل من عميل المقبس والخادم وقراءته مرة واحدة. في الواقع ، إذا كان مقدار البيانات كبيرًا بشكل خاص خلال كل اتصال ، فلا يمكن أن يقبله الخادم. يمكن أن تقرأها ومعالجتها عند تحديد عدد بايت البيانات المطلوبة من قبل العميل.
بالإضافة إلى ذلك ، إذا لم يكن الدفق المذكور أعلاه ملفوفًا ، فستكون هناك خسائر في الأداء في الممارسة العملية ، مثل عدم القدرة على المخزن المؤقت ، إلخ.
بالنسبة لبيانات استلام خادم المقبس ، يكون الأمر أكثر ملاءمة إذا كان يمكن تخزين بيانات البايت من حلقات متعددة من خلال مخزن مؤقت للبايت المتغير. ومع ذلك ، باستخدام bytearrayoutputstream ، على سبيل المثال:
ByteArrayoutputStream Data = new ByTearRayoutputStream () ؛ data.write (recebuffer ، totalbytes ، totalBytes + receptbytes) ؛
اختبار الاتصال الحيوي
الاختبارات التالية كفاءة معالجة خادم المقبس في سيناريو مع عدد كبير من الطلبات.
الطريقة الأولى: ابدأ 5000 عميل Socket من خلال حلقة وأرسل طلبًا. الرمز كما يلي:
public static void main (string [] args) {int n = 5000 ؛ DataBuffer Data = new StringBuffer () ؛ تاريخ البدء = تاريخ جديد () ؛ لـ (int i = 0 ؛ i <n ؛ i ++) {data.delete (0 ، data.length ()) ؛ data.append ("أنا العميل") .append (++ pos) .append (".") ؛ CompleBiotCpclient Client = new SimpleBiotCpclient ("LocalHost" ، 1983) ؛ client.send (data.toString (). getBytes ()) ؛ } نهاية التاريخ = تاريخ جديد () ؛ تكلفة طويلة = end.getTime () - start.getTime () ؛ System.out.println (N + "طلبات التكلفة" + التكلفة + "MS.") ؛ } بعد الاختبار ، يستغرق حوالي 9864 مللي ثانية ، أي حوالي 10s.
الطريقة الثانية: ابدأ 5000 مؤشرات ترابط عميل مستقلة وطلب في نفس الوقت ، ويعداد الخادم:
حزمة 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 */ public class simplebiotcptest {static int threadcount = 5000 ؛ / *** عملية خادم المقبس استنادًا إلى Bio** Author Shieldrn*/ static class SocketServer تمتد مؤشر ترابط {/ ** رقم منفذ الخدمة*/ private int port = 8888 ؛ / ** قم بتعيين رقم للعميل*/ تسلسل int الثابت الخاص = 0 ؛ SocketServer (int port) {this.port = port ؛ } Override public void run () {Socket Socket = null ؛ العداد int = 0 ؛ جرب {serversocket severocket = new servers (this.port) ؛ العلم المنطقي = خطأ ؛ تاريخ البدء = فارغ ؛ بينما (صواب) {socket = serversOcket.accept () ؛ // الاستماع// الوقت يبدأ if (! flag) {start = new date () ؛ العلم = صحيح ؛ } this.handlemessage (socket) ؛ // التعامل مع طلب عميل متصل إذا (++ counter == threadCount) {date end = new date () ؛ long last = end.getTime () - start.getTime () ؛ System.out.println (ThreadCount + "COSTS COST" + Last + "MS.") ؛ }}}} catch (ioException e) {E.PrintStackTrace () ؛ }} / ** * تعامل مع اتصال مقبس العميل * Param Socket Client Socket * Throws IOException * / private void handlemessage (Socket Socket) يلقي iOexception {inputStream في = socket.getInputStream () ؛ // دفق: client-> server (read) outputStream out = socket.getOutputStream () ؛ // دفق: server-> client (write) intbytes ؛ byte [] receptbuffer = new byte [128] ؛ سلسلة clientMessage = "" ؛ if ((receberBytes = in.Read (recebuffer))! =-1) {clientMessage = new string (recebuffer ، 0 ، receptbytes) ؛ if (clientMessage.startswith ("أنا العميل")) {String serverResponseWords = "أنا الخادم ، وأنت" + (++ تسلسل) + "العميل TH." ؛ out.write (serverResponsewords.getBytes ()) ؛ }} out.flush () ؛ System.out.println ("الخادم: يتلقى clientMessage->" + clientMessage) ؛ }} / ** * مؤشر ترابط عميل المقبس استنادًا إلى Bio * * Author Shieldrn * / static class SocketClient تنفذ Runnable {private string ipaddress ؛ منفذ الباحث الخاص ؛ / ** طلب البيانات ليتم إرسالها*/ بيانات السلسلة الخاصة ؛ SocketClient العامة (سلسلة ipaddress ، منفذ int) {this.ipaddress = ipaddress ؛ this.port = port ؛ } Override public void run () {this.send () ؛ } / *** قم بالاتصال بخادم المقبس ومحاكاة إرسال بيانات الطلب* / public void send () {Socket Socket = null ؛ OutputStream Out = null ؛ inputStream في = null ؛ Try {Socket = New Socket (this.ipaddress ، this.port) ؛ // connect // send request Out = Socket.getOutputStream () ؛ out.write (data.getBytes ()) ؛ out.flush () ؛ // استقبال استجابة في = socket.getInputStream () ؛ int totalBytes = 0 ؛ int recebytes = 0 ؛ byte [] receptbuffer = new byte [128] ؛ if ((receberBytes = in.Read (recebuffer))! =-1) {totalBytes += receberbytes ؛ } string serverMessage = new string (recebuffer ، 0 ، receptbytes) ؛ system.out.println ("العميل: يستقبل serverMessage->" + serverMessage) ؛ } catch (unknownHostException e) {E.PrintStackTrace () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ } أخيرًا {try {// أرسل طلبًا واستلام استجابة ، يتم الانتهاء من الاتصال ، وأغلق الاتصال Out.Close () ؛ in.close () ؛ socket.close () ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}} public void setData (string data) {this.data = data ؛ }} public static void main (string [] args) يلقي الاستثناء {SocketServer Server = جديد SocketServer (1983) ؛ server.start () ؛ thread.sleep (3000) ؛ لـ (int i = 0 ؛ i <threadcount ؛ i ++) {socketClient client = new SocketClient ("LocalHost" ، 1983) ؛ client.setData ("أنا العميل" + (i + 1) + ".") ؛ موضوع جديد (عميل) .start () ؛ thread.sleep (0 ، 1) ؛ }}}بعد الاختبار ، يستغرق حوالي 7110 مللي ثانية ، أي حوالي 7s ، وليس هناك تحسن كبير.
تحسينات التواصل الحيوي
من خلال الاختبارات المذكورة أعلاه ، يمكننا أن نجد أنه عندما يعالج خادم المقبس طلبات من العميل ، يحدث الحظر ، مما يؤثر بشكل خطير على كفاءة المعالجة المتزامنة للطلبات. في الواقع ، في نطاق إمكانية اتصال خادم المقبس ، يمكن أن يكون الطلب المستلم مستقلًا ، وذلك لحل المشكلة أعلاه عن طريق معالجة الطلبات حسب طلب واحد وخيط واحد. وبهذه الطريقة ، يحتوي جانب الخادم على مؤشرات ترابط معالجة متعددة تقابل الطلبات المتعددة للعميل ، وقد تم تحسين كفاءة المعالجة إلى حد ما.
أدناه ، تلقي الطلب من خلال سلسلة رسائل واحدة ، ثم تفويض تجمع مؤشرات الترابط لأداء طلبات المعالجة المتزامنة متعددة الخيوط:
/ *** عملية خادم المقبس استنادًا إلى Bio** Author Shieldrn*/ static class SocketServer تمتد مؤشر ترابط {/ ** رقم منفذ الخدمة*/ private int port = 8888 ؛ / ** تعيين رقم إلى العميل*/ تسلسل int الثابت الخاص = 0 ؛ / ** تجمع مؤشرات الترابط لمعالجة طلبات العميل*/ Private ExecutorService Pool ؛ socketserver العامة (int port ، int poolsize) {this.port = port ؛ this.pool = Executors.NewFixedThreadPool (poolsize) ؛ } Override public void run () {Socket Socket = null ؛ العداد int = 0 ؛ جرب {serversocket severocket = new servers (this.port) ؛ العلم المنطقي = خطأ ؛ تاريخ البدء = فارغ ؛ بينما (صواب) {socket = serversOcket.accept () ؛ // الاستماع // يبدأ الوقت إذا جاء طلب إذا (! flag) {start = new date () ؛ العلم = صحيح ؛ } // ضع طلب العميل في تجمع مؤشرات الترابط إلى Process Pool.execute (New requestHandler (Socket)) ؛ if (++ counter == threadCount) {date end = new date () ؛ long last = end.getTime () - start.getTime () ؛ System.out.println (ThreadCount + "COSTS COST" + Last + "MS.") ؛ }}} catch (ioException e) {E.PrintStackTrace () ؛ }} / ** * فئة مؤشر ترابط معالجة طلب العميل * * Author shieldrn * / class requestHandler تنفذ Runnable {private Socket Socket ؛ requestHandler (Socket Socket) {this.socket = socket ؛ } Override public void run () {try {inputStream in = socket.getInputStream () ؛ // دفق: client-> server (read) outputStream out = socket.getOutputStream () ؛ // دفق: server-> client (write) intbytes ؛ byte [] receptbuffer = new byte [128] ؛ سلسلة clientMessage = "" ؛ if ((receberBytes = in.Read (recebuffer))! =-1) {clientMessage = new string (recebuffer ، 0 ، receptbytes) ؛ if (clientMessage.startswith ("أنا العميل")) {String serverResponseWords = "أنا الخادم ، وأنت" + (++ تسلسل) + "العميل TH." ؛ out.write (serverResponsewords.getBytes ()) ؛ }} out.flush () ؛ System.out.println ("الخادم: يتلقى clientMessage->" + clientMessage) ؛ } catch (ioException e) {E.PrintStackTrace () ؛ }}}}}}}}}يمكن ملاحظة أن هذه الطريقة المحسنة تعزز توافق طلبات معالجة الخادم ، ولكن يجب معالجة كل طلب بواسطة مؤشر ترابط. يتسبب عدد كبير من الطلبات في بدء تشغيل الخادم عددًا كبيرًا من العمليات للمعالجة ، والذي يحتل أيضًا موارد الخادم نسبيًا.
ما سبق هو كل محتوى هذه المقالة. آمل أن يكون ذلك مفيدًا لتعلم الجميع وآمل أن يدعم الجميع wulin.com أكثر.