在看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 閱讀(1484)
評論(0) 編輯 收藏 所屬分類:
Core Java