四注冊與處理過程詳解 接下來我們要分析Connection的register()方法
前面我們總是說用Selector注冊的連接
其實這是一種簡化的說法
實際上
用Selector注冊的是一個java
nio
channels
SocketChannel對象
但只針對特定的I/O操作
注冊之後
有一個java
nio
channels
SelectionKey被返回
這個選擇鍵可以通過attach()方法關聯到任意對象
為了通過鍵獲得連接
這裡把Connection對象關聯到鍵
這樣
我們就可以從Selector間接地獲得一個Connection
public void register(Selector selector)
throws IOException {
key = socketChannel
register(selector
SelectionKey
OP_READ);
key
attach(this);
}
回過頭來看ConnectionSelector
select()方法的返回值表示有多少連接已經做好了I/O操作的准備
如果返回值是
則返回
否則
調用selectedKeys()獲得鍵的集合(Set)
從這些鍵獲得以前關聯的Connection對象
然後調用其readRequest()或writeResponse()方法
具體調用哪一個方法由連接被注冊為讀取操作還是寫入操作決定
現在再來看Connection類
Connection類代表著連接
處理所有協議有關的細節
在構造函數中
通過參數傳入的SocketChannel被設置成非阻塞模式
這對於服務器來說是很重要的
另外
構造函數還設置了一些默認值
分配了緩沖區requestLineBuffer
由於分配直接緩沖區代價稍高
且這裡的每一個連接都用一個新的緩沖區
因此這裡使用java
nio
ByteBuffer
allocate()而不是ByteBuffer
allocateDirect()
如果重用緩沖區
直接緩沖區可能具有更高的效率
public Connection(SocketChannel socketChannel)
throws IOException {
this
socketChannel = socketChannel;
nfigureBlocking(false);
requestLineBuffer = ByteBuffer
allocate(
);
}
完成所有初始化工作且SocketChannel做好了讀取准備之後
ConnectionSelector調用了readRequest()方法
利用socketChannel
read(requestLineBuffer)方法把所有可用的數據讀入緩沖區
如果不能讀取完整的行
則返回發出調用的ConnectionSelector
允許另一個連接進入處理過程
反之
如果成功地讀取了整個行
接下來應該做的是象在Httpd中一樣解析請求
如果當前的請求合法
程序為請求目標文件創建一個java
nio
Channels
FileChannel
並調用prepareForResponse()方法
private void prepareForResponse() throws IOException {
StringBuffer responseLine = new StringBuffer(
);
responseLineBuffer = ByteBuffer
wrap(
responseLine
toString()
getBytes(
ASCII
)
);
key
interestOps(SelectionKey
OP_WRITE);
key
selector()
wakeup();
}
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27638.html