上善若水
          In general the OO style is to use a lot of little objects with a lot of little methods that give us a lot of plug points for overriding and variation. To do is to be -Nietzsche, To bei is to do -Kant, Do be do be do -Sinatra
          posts - 146,comments - 147,trackbacks - 0
          在看Jetty源碼中的EndPointTest類,對EndPoint的測試,我的思路是:
          1. 建立一個連接(創建ServerSocket實例,一般還會給定一個端口,其實可以bind(null)以讓操作系統分配一個可用端口),新啟動一個線程,在新線程中監聽給定端口(調用accept方法)。
          2. 發送客戶端請求(創建一個Socket實例,并向該Socket寫入請求數據)。
          3. 在接收端讀取數據,驗證寫入的請求和接收到的數據相同。

          在以上流程實現中,accept方法返回的接收端Socket需要傳給主線程,同時要保證使用該Socket是在accept方法返回之后,以我習慣,我會使用一個Lock或CountDownLatch:
          private static class SocketHolder {
              Socket socket;
          }

          @Test
          public void levinOldWayTest() throws Exception {
              final ServerSocket server = new ServerSocket(10240);
              
              final CountDownLatch latch = new CountDownLatch(1);
              final SocketHolder socketHolder = new SocketHolder();
              new Thread() {
                  public void run() {
                      try {
                          socketHolder.socket = server.accept();
                          latch.countDown();
                      } catch(Exception ex) {
                          ex.printStackTrace();
                      }
                  }
              }.start();
              
              Socket socket = new Socket(server.getInetAddress(), server.getLocalPort());
              socket.getOutputStream().write("My Test String".getBytes());
              
              latch.await(5, TimeUnit.SECONDS);
              byte[] receives = new byte[4096];
              int length = socketHolder.socket.getInputStream().read(receives);
              
              assertEquals("My Test String", new String(receives, 0, length));
              
              socket.close();
              socketHolder.socket.close();
              server.close();
          }

          不知道有多少人也像我一樣把這段代碼寫成這樣?這里有兩個問題:
          1. ServerSocket的監聽的端口不一定是可用的,類似測試代碼我之前沒有寫過,我估計自己正真在寫的時候應該會想到讓操作系統動態分配。
          2. 為了在兩個線程中傳遞數據,這里首先創建了一個SocketHolder類,然后使用CountDownLatch,寫起來好麻煩。為了簡化這段代碼,可以使用Exchanger,即當一個生產者線程準備好數據后可以通過Exchanger將數據傳遞給消費者,而消費者在生產者傳遞過來數據后就可以消費了,這里的數據就是Socket。

          改進后的代碼如下:
          @Test
          public void levinImprovedWayTest() throws Exception {
              final ServerSocket server = new ServerSocket();
              server.bind(null);
              
              final Exchanger<Socket> exchanger = new Exchanger<Socket>();
              new Thread() {
                  public void run() {
                      try {
                          exchanger.exchange(server.accept());
                      } catch(Exception ex) {
                          ex.printStackTrace();
                      }
                  }
              }.start();
              
              Socket socket = new Socket(server.getInetAddress(), server.getLocalPort());
              socket.getOutputStream().write("My Test String".getBytes());
              
              Socket receiverSocket = exchanger.exchange(null, 5, TimeUnit.SECONDS);
              byte[] receives = new byte[4096];
              int length = receiverSocket.getInputStream().read(receives);
              
              assertEquals("My Test String", new String(receives, 0, length));
              
              socket.close();
              receiverSocket.close();
              server.close();
          }
          posted on 2014-03-23 13:40 DLevin 閱讀(1487) 評論(0)  編輯  收藏 所屬分類: Core Java
          主站蜘蛛池模板: 中牟县| 页游| 黄大仙区| 奉新县| 余庆县| 隆尧县| 竹北市| 台东县| 桐城市| 石屏县| 工布江达县| 剑河县| 中卫市| 新龙县| 赤水市| 大新县| 璧山县| 乐山市| 新田县| 得荣县| 宁化县| 武强县| 碌曲县| 汉阴县| 太康县| 奉化市| 尖扎县| 垦利县| 班玛县| 福州市| 治多县| 上杭县| 朝阳县| 天等县| 夏河县| 广平县| 台前县| 揭西县| 资中县| 甘孜县| 景洪市|