亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

基于BIO的Java Socket通信詳解

2024-07-13 10:14:44
字體:
來源:轉載
供稿:網友

BIO,即阻塞IO,在基于Socket的消息通信過程中,Socket服務端向外部提供服務,而Socket客戶端可以建立到Socket服務端的連接,進而發送請求數據,然后等待Socket服務端處理,并返回處理結果(響應)。
基于BIO的通信,Socket服務端會發生阻塞,即在監聽過程中每次accept到一個客戶端的Socket連接,就要處理這個請求,而此時其他連接過來的客戶端只能阻塞等待??梢?,這種模式下Socket服務端的處理能力是非常有限的,客戶端也只能等待,直到服務端空閑時進行請求的處理。

BIO通信實現

下面基于BIO模式,來實現一個簡單的Socket服務端與Socket客戶端進行通信的邏輯,對這種通信方式有一個感性的認識。具體邏輯描述如下:
1、Socket客戶端連接到Socket服務端,并發送數據“I am the client N.”;
2、Socket服務端,監聽服務端口,并接收客戶端請求數據,如果請求數據以“I am the client”開頭,則響應客戶端“I am the server, and you are the Nth client.”;

Socket服務端實現,代碼如下所示:

package org.shirdrn.java.communications.bio;  import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket;  /**  * 基于BIO的Socket服務器端  *  * @author shirdrn  */ public class SimpleBioTcpServer extends Thread {      /** 服務端口號 */   private int port = 8888;   /** 為客戶端分配編號 */   private static int sequence = 0;      public SimpleBioTcpServer(int port) {     this.port = port;   }      @Override   public void run() {     Socket socket = null;     try {       ServerSocket serverSocket = new ServerSocket(this.port);       while(true) {         socket = serverSocket.accept(); // 監聽         this.handleMessage(socket); // 處理一個連接過來的客戶端請求       }     } catch (IOException e) {       e.printStackTrace();     }   }      /**    * 處理一個客戶端socket連接    * @param socket 客戶端socket    * @throws IOException    */   private void handleMessage(Socket socket) throws IOException {     InputStream in = socket.getInputStream(); // 流:客戶端->服務端(讀)     OutputStream out = socket.getOutputStream(); // 流:服務端->客戶端(寫)     int receiveBytes;     byte[] receiveBuffer = new byte[128];     String clientMessage = "";     if((receiveBytes=in.read(receiveBuffer))!=-1) {       clientMessage = new String(receiveBuffer, 0, receiveBytes);       if(clientMessage.startsWith("I am the client")) {         String serverResponseWords =            "I am the server, and you are the " + (++sequence) + "th client.";         out.write(serverResponseWords.getBytes());       }     }     out.flush();     System.out.println("Server: receives clientMessage->" + clientMessage);   }    public static void main(String[] args) {     SimpleBioTcpServer server = new SimpleBioTcpServer(1983);     server.start();   } } 

上述實現,沒有進行復雜的異常處理。

Socket客戶端實現,代碼如下所示:

package org.shirdrn.java.communications.bio;  import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; import java.util.Date;  /**  * 基于BIO的Socket客戶端  *  * @author shirdrn  */ public class SimpleBioTcpClient {      private String ipAddress;   private int port;   private static int pos = 0;      public SimpleBioTcpClient() {}      public SimpleBioTcpClient(String ipAddress, int port) {     this.ipAddress = ipAddress;     this.port = port;   }    /**    * 連接Socket服務端,并模擬發送請求數據    * @param data 請求數據    */   public void send(byte[] data) {     Socket socket = null;     OutputStream out = null;     InputStream in = null;     try {       socket = new Socket(this.ipAddress, this.port); // 連接       // 發送請求       out = socket.getOutputStream();       out.write(data);        out.flush();       // 接收響應       in = socket.getInputStream();       int totalBytes = 0;       int receiveBytes = 0;       byte[] receiveBuffer = new byte[128];       if((receiveBytes=in.read(receiveBuffer))!=-1) {         totalBytes += receiveBytes;       }       String serverMessage = new String(receiveBuffer, 0, receiveBytes);       System.out.println("Client: receives serverMessage->" + serverMessage);     } catch (UnknownHostException e) {       e.printStackTrace();     } catch (IOException e) {       e.printStackTrace();     } catch (Exception e) {       e.printStackTrace();     } finally {       try {         // 發送請求并接收到響應,通信完成,關閉連接         out.close();         in.close();         socket.close();       } catch (IOException e) {         e.printStackTrace();       }     }   }    public static void main(String[] args) {     int n = 1;     StringBuffer data = new StringBuffer();     Date start = new Date();     for(int i=0; i<n; i++) {       data.delete(0, data.length());       data.append("I am the client ").append(++pos).append(".");       SimpleBioTcpClient client = new SimpleBioTcpClient("localhost", 1983);       client.send(data.toString().getBytes());     }     Date end = new Date();     long cost = end.getTime() - start.getTime();     System.out.println(n + " requests cost " + cost + " ms.");   } } 

首先啟動Socket服務端進程SimpleBioTcpServer,然后再運行Socket客戶端SimpleBioTcpClient??梢钥吹?,服務端接收到請求數據,然后響應客戶端,客戶端接收到了服務端的響應數據。

上述實現中,對于Socket客戶端和服務端都是一次寫入,并一次讀出,而在實際中如果每次通信過程中數據量特別大的話,服務器端是不可能接受的,可以在確定客戶端請求數據字節數的情況,循環來讀取并進行處理。

另外,對于上述實現中流沒有進行裝飾(Wrapped)處理,在實際中會有性能的損失,如不能緩沖等。

對于Socket服務端接收數據,如果可以使多次循環讀取到的字節數據通過一個可變長的字節緩沖區來存儲,就能方便多了,可是使用ByteArrayOutputStream,例如:

ByteArrayOutputStream data = new ByteArrayOutputStream(); data.write(receiveBuffer, totalBytes , totalBytes + receiveBytes); 

BIO通信測試

下面測試一下大量請求的場景下,Socket服務端處理的效率。

第一種方式:通過for循環來啟動5000個Socket客戶端,發送請求,代碼如下所示:

public static void main(String[] args) {   int n = 5000;   StringBuffer data = new StringBuffer();   Date start = new Date();   for(int i=0; i<n; i++) {     data.delete(0, data.length());     data.append("I am the client ").append(++pos).append(".");     SimpleBioTcpClient client = new SimpleBioTcpClient("localhost", 1983);     client.send(data.toString().getBytes());   }   Date end = new Date();   long cost = end.getTime() - start.getTime();   System.out.println(n + " requests cost " + cost + " ms."); } 

經過測試,大約需要9864ms,大概接近10s。

第二種方式:通過啟動5000個獨立的客戶端線程,同時請求,服務端進行計數:

package org.shirdrn.java.communications.bio;  import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import java.util.Date;  /**  * 基于BIO的Socket通信測試  *  * @author shirdrn  */ public class SimpleBioTcpTest {      static int threadCount = 5000;      /**    * 基于BIO的Socket服務端進程    *    * @author shirdrn    */   static class SocketServer extends Thread {          /** 服務端口號 */     private int port = 8888;     /** 為客戶端分配編號 */     private static int sequence = 0;          public SocketServer(int port) {       this.port = port;     }          @Override     public void run() {       Socket socket = null;       int counter = 0;       try {         ServerSocket serverSocket = new ServerSocket(this.port);         boolean flag = false;         Date start = null;         while(true) {           socket = serverSocket.accept(); // 監聽           // 有請求到來才開始計時           if(!flag) {             start = new Date();             flag = true;           }           this.handleMessage(socket); // 處理一個連接過來的客戶端請求           if(++counter==threadCount) {             Date end = new Date();             long last = end.getTime() - start.getTime();             System.out.println(threadCount + " requests cost " + last + " ms.");           }         }       } catch (IOException e) {         e.printStackTrace();       }     }          /**      * 處理一個客戶端socket連接      * @param socket 客戶端socket      * @throws IOException      */     private void handleMessage(Socket socket) throws IOException {       InputStream in = socket.getInputStream(); // 流:客戶端->服務端(讀)       OutputStream out = socket.getOutputStream(); // 流:服務端->客戶端(寫)       int receiveBytes;       byte[] receiveBuffer = new byte[128];       String clientMessage = "";       if((receiveBytes=in.read(receiveBuffer))!=-1) {         clientMessage = new String(receiveBuffer, 0, receiveBytes);         if(clientMessage.startsWith("I am the client")) {           String serverResponseWords =              "I am the server, and you are the " + (++sequence) + "th client.";           out.write(serverResponseWords.getBytes());         }       }       out.flush();       System.out.println("Server: receives clientMessage->" + clientMessage);     }   }      /**    * 基于BIO的Socket客戶端線程    *    * @author shirdrn    */   static class SocketClient implements Runnable {          private String ipAddress;     private int port;     /** 待發送的請求數據 */     private String data;          public SocketClient(String ipAddress, int port) {       this.ipAddress = ipAddress;       this.port = port;     }      @Override     public void run() {       this.send();           }          /**      * 連接Socket服務端,并模擬發送請求數據      */     public void send() {       Socket socket = null;       OutputStream out = null;       InputStream in = null;       try {         socket = new Socket(this.ipAddress, this.port); // 連接         // 發送請求         out = socket.getOutputStream();         out.write(data.getBytes());          out.flush();         // 接收響應         in = socket.getInputStream();         int totalBytes = 0;         int receiveBytes = 0;         byte[] receiveBuffer = new byte[128];         if((receiveBytes=in.read(receiveBuffer))!=-1) {           totalBytes += receiveBytes;         }         String serverMessage = new String(receiveBuffer, 0, receiveBytes);         System.out.println("Client: receives serverMessage->" + serverMessage);       } catch (UnknownHostException e) {         e.printStackTrace();       } catch (IOException e) {         e.printStackTrace();       } catch (Exception e) {         e.printStackTrace();       } finally {         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) throws Exception {     SocketServer server = new SocketServer(1983);     server.start();          Thread.sleep(3000);          for(int i=0; i<threadCount; i++) {       SocketClient client = new SocketClient("localhost", 1983);       client.setData("I am the client " + (i+1) + ".");       new Thread(client).start();       Thread.sleep(0, 1);     }       } }

 經過測試,大約需要7110ms,大概接近7s,沒有太大提高。

BIO通信改進

通過上面的測試我們可以發現,在Socket服務端對來自客戶端的請求進行處理時,會發生阻塞,嚴重地影響了能夠并發處理請求的效率。實際上,在Socket服務端接收來自客戶端連接能力的范圍內,可以將接收請求獨立出來,從而在將處理請求獨立粗話來,通過一個請求一個線程處理的方式來解決上述問題。這樣,服務端是多處理線程對應客戶端多請求,處理效率有一定程度的提高。

下面,通過單線程接收請求,然后委派線程池進行多線程并發處理請求:

/**    * 基于BIO的Socket服務端進程    *    * @author shirdrn    */   static class SocketServer extends Thread {          /** 服務端口號 */     private int port = 8888;     /** 為客戶端分配編號 */     private static int sequence = 0;     /** 處理客戶端請求的線程池 */     private ExecutorService pool;          public SocketServer(int port, int poolSize) {       this.port = port;       this.pool = Executors.newFixedThreadPool(poolSize);     }          @Override     public void run() {       Socket socket = null;       int counter = 0;       try {         ServerSocket serverSocket = new ServerSocket(this.port);         boolean flag = false;         Date start = null;         while(true) {           socket = serverSocket.accept(); // 監聽           // 有請求到來才開始計時           if(!flag) {             start = new Date();             flag = true;           }           // 將客戶端請求放入線程池處理           pool.execute(new RequestHandler(socket));           if(++counter==threadCount) {             Date end = new Date();             long last = end.getTime() - start.getTime();             System.out.println(threadCount + " requests cost " + last + " ms.");           }         }       } catch (IOException e) {         e.printStackTrace();       }     }          /**      * 客戶端請求處理線程類      *      * @author shirdrn      */     class RequestHandler implements Runnable {        private Socket socket;              public RequestHandler(Socket socket) {         this.socket = socket;       }              @Override       public void run() {         try {           InputStream in = socket.getInputStream(); // 流:客戶端->服務端(讀)           OutputStream out = socket.getOutputStream(); // 流:服務端->客戶端(寫)           int receiveBytes;           byte[] receiveBuffer = new byte[128];           String clientMessage = "";           if((receiveBytes=in.read(receiveBuffer))!=-1) {             clientMessage = new String(receiveBuffer, 0, receiveBytes);             if(clientMessage.startsWith("I am the client")) {               String serverResponseWords =                  "I am the server, and you are the " + (++sequence) + "th client.";               out.write(serverResponseWords.getBytes());             }           }           out.flush();           System.out.println("Server: receives clientMessage->" + clientMessage);         } catch (IOException e) {           e.printStackTrace();         }               }     }   } 

可見,這種改進方式增強服務端處理請求的并發度,但是每一個請求都要由一個線程去處理,大量請求造成服務端啟動大量進程進行處理,也是比較占用服務端資源的。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲黄色av女优在线观看| 亚洲国产成人久久综合| 欧美日韩中文字幕日韩欧美| 国产日韩精品一区二区| 国产视频欧美视频| 国产成人精品午夜| 欧美中文在线字幕| 九九热这里只有在线精品视| 日韩在线视频中文字幕| 91极品视频在线| 91精品久久久久久久久久另类| 欧美成人小视频| 久久久久亚洲精品国产| 国产成人啪精品视频免费网| 亚洲成人av片在线观看| 中文字幕自拍vr一区二区三区| 国产精品视频一区国模私拍| 久久久久久久久久亚洲| 91po在线观看91精品国产性色| 疯狂欧美牲乱大交777| 色先锋久久影院av| 自拍偷拍亚洲区| 国产综合视频在线观看| 久久亚洲综合国产精品99麻豆精品福利| 日韩成人免费视频| 国产91九色视频| 国产精品网红直播| 性欧美激情精品| 国产精品久久久久久久久久小说| 国产精品电影观看| 日韩一区二区福利| 精品国偷自产在线视频| 日韩在线观看电影| 亚洲片在线观看| 日本一欧美一欧美一亚洲视频| 欧美美最猛性xxxxxx| 亚洲欧美日韩天堂| 色综合久久88色综合天天看泰| 国产精品久久久久久一区二区| 国模吧一区二区| 欧美亚洲视频在线看网址| 国产精品狠色婷| 在线观看欧美日韩国产| 色狠狠av一区二区三区香蕉蜜桃| 亚洲精品电影网在线观看| 国产午夜一区二区| 性欧美在线看片a免费观看| 午夜精品一区二区三区视频免费看| 欧美午夜宅男影院在线观看| 亚洲中国色老太| 亚洲欧美日韩中文在线| 久久人91精品久久久久久不卡| 97国产成人精品视频| 久久999免费视频| 日韩电影免费在线观看中文字幕| 亚洲自拍高清视频网站| 亚洲人成欧美中文字幕| 久99久在线视频| 久久这里只有精品视频首页| 欧美一区三区三区高中清蜜桃| 久久视频在线播放| 亚洲男人的天堂在线播放| 欧美亚洲视频一区二区| 亚洲v日韩v综合v精品v| 91九色视频在线| 精品久久久久久中文字幕| 精品免费在线视频| 亚洲一二三在线| 久久久噜噜噜久噜久久| 欧美成人免费全部观看天天性色| 久久成人综合视频| 日韩欧美在线观看| 国产激情999| 亚洲va久久久噜噜噜久久天堂| 日韩欧美高清视频| 欧美巨大黑人极品精男| 午夜精品一区二区三区在线视频| 成人性生交大片免费看小说| 成人免费观看49www在线观看| 国产精品高潮呻吟久久av无限| 欧洲一区二区视频| 亚洲91精品在线| 日韩在线视频中文字幕| 亚洲最大的av网站| 成年无码av片在线| 久久夜色精品国产欧美乱| 亚洲男人天堂2024| 人妖精品videosex性欧美| 欧美怡春院一区二区三区| 高清一区二区三区四区五区| 日韩国产在线播放| 亚洲精品动漫100p| 欧美精品18videos性欧| 亚洲va电影大全| 狠狠色狠色综合曰曰| 美女性感视频久久久| 国产精品视频99| 麻豆精品精华液| 精品高清美女精品国产区| 久久久国产精品亚洲一区| 亚洲国产成人久久综合一区| 综合欧美国产视频二区| 成人性生交大片免费看小说| 操人视频在线观看欧美| 欧美成人免费va影院高清| 欧美电影免费播放| 欧美成人精品在线观看| 国产主播精品在线| 亚洲欧美日韩第一区| 中文字幕亚洲天堂| 亚洲国产成人精品一区二区| 精品国产成人av| 欧洲永久精品大片ww免费漫画| 久久亚洲一区二区三区四区五区高| 91九色单男在线观看| 成人网中文字幕| 清纯唯美亚洲激情| 日韩资源在线观看| 久久久久日韩精品久久久男男| 久久久精品一区二区| 孩xxxx性bbbb欧美| 午夜精品福利视频| 久久精品视频99| 久久97精品久久久久久久不卡| 91久久中文字幕| 日韩福利在线播放| 性金发美女69hd大尺寸| 日韩在线观看免费高清完整版| 日本一区二区在线免费播放| 456国产精品| 亚洲人永久免费| 伊人青青综合网站| 奇门遁甲1982国语版免费观看高清| 国产aⅴ夜夜欢一区二区三区| 国产精品亚洲欧美导航| 日韩欧美在线一区| 亚洲国产精品久久久久久| 欧美高清电影在线看| 日韩中文字幕av| 一本色道久久综合狠狠躁篇怎么玩| 亚洲欧洲一区二区三区久久| 国产成人精品综合| 亚洲精品一区二区网址| 亚洲国产天堂久久综合| 国产精品你懂得| 欧美一级免费视频| 91精品久久久久久| 亚洲天堂影视av| 国内精品久久久久久影视8| 日韩av在线导航| 91成人国产在线观看| 欧美国产高跟鞋裸体秀xxxhd| 日韩成人av在线播放| 亚洲国产成人一区| 国产一区二区三区免费视频| 亚洲色图欧美制服丝袜另类第一页| 欧美亚洲激情视频| 国产一区二区视频在线观看| 97热在线精品视频在线观看| 97国产在线视频| 亚洲精品99久久久久| 深夜精品寂寞黄网站在线观看| 97久久精品人人澡人人爽缅北| 日韩精品久久久久久福利|