第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

非阻塞 Java SocketChannel 介紹

1. 前言

前一小節(jié)介紹了 Java NIO Channel 體系結(jié)構(gòu),其中 java.nio.channels.SocketChannel 和 java.nio.channels.ServerSocketChannel 是編寫非阻塞 Java TCP Soccket 程序的重要模塊。SocketChanel 用在 TCP 的客戶端和服務(wù)器端,用于數(shù)據(jù)的讀寫。SocketChannel 表示一個 Endpoint,并且和遠(yuǎn)端的 SocketChannel 建立了連接。ServerSocketChannel 用于創(chuàng)建 TCP 服務(wù)器,用于監(jiān)聽新的 TCP 連接請求。本小節(jié)對 SocketChannel 和 ServerSocketChannel 的基本功能做一個初步的分析。

2. SocketChannel 介紹

SocketChannel 的基本功能就是用于 TCP 連接的建立,數(shù)據(jù)讀寫,TCP 連接關(guān)閉。

2.1 SocketChannel 實例創(chuàng)建

SocketChannel 并沒有提供 public 構(gòu)造方法,創(chuàng)建 SocketChannel 的實例需要通過工廠方法 open 實現(xiàn)。open 聲明如下:

public static SocketChannel open() throws IOException
public static SocketChannel open(SocketAddress remote) throws IOException

SocketChannel 的不帶參數(shù)的 open 方法只是創(chuàng)建實例,不會 connect 服務(wù)器,帶參的 open 方法會 connect 遠(yuǎn)端服務(wù)器。如果是創(chuàng)建阻塞式 SocketChannel,可以通過 open 方法傳入遠(yuǎn)端服務(wù)器的地址;如果是創(chuàng)建非阻塞式 SocketChannel 需要調(diào)用不帶參數(shù)的 open 方法,然后再調(diào)用 connect 方法連接遠(yuǎn)端服務(wù)器。

2.2 SocketChannel 的 connect 方法

SocketChannel 提供了專門 connect 方法,可以進(jìn)行阻塞式、非阻塞式連接。聲明如下:

public abstract boolean connect(SocketAddress remote) throws IOException;
public abstract boolean finishConnect() throws IOException

如果 SocketChannel 是阻塞模式,調(diào)用它的 connect 方法連接遠(yuǎn)端服務(wù)器,connect 方法會執(zhí)行阻塞式調(diào)用,直到連接成功或者失敗返回。
如果 SocketChannel 是非阻塞模式,調(diào)用它的 connect 方法連接遠(yuǎn)端服務(wù)器,connect 方法會執(zhí)行非阻塞式調(diào)用。connect 發(fā)出連接請求后,不管 TCP 連接是否成功,都會馬上返回。必須調(diào)用 finishConnect 方法,檢查連接是否成功,如果連接成功 finishConnect,返回 true;如果連接沒有成功,finishConnect 返回 false。

2.3 SocketChannel 的數(shù)據(jù)讀取

SocketChannel 提供了讀取單片數(shù)據(jù)的方法,聲明如下:

public abstract int read(ByteBuffer dst) throws IOException

其實,單片數(shù)據(jù)的 read 方法是重寫了 java.nio.channels.ReadableByteChannel 中的 read 方法。 read 方法是從 I/O 設(shè)備讀取數(shù)據(jù),保存在 ByteBuffer 中,為此調(diào)用者必須提供 ByteBuffer 用以保存數(shù)據(jù)。返回值是讀取的字節(jié)數(shù)、0、或者 -1。如果是阻塞式 Channel,read 至少返回 1 或者 -1;如果是非阻塞式 Chanel,read 可能會返回 0。

SocketChannel 提供了讀取多片數(shù)據(jù)的方法,聲明如下:

public final long read(ByteBuffer[] dsts) throws IOException
public final long read(ByteBuffer[] dsts, int offset, int length) throws IOException

其實,多片數(shù)據(jù)的 read 方法是重寫了 java.nio.channels.ScatteringByteChannel 中的 read 方法。多片數(shù)據(jù) read 方法的返回值和單片數(shù)據(jù) read 方法的返回值具有相同的含義。多片數(shù)據(jù)的 read 方法,其實是將 TCP 字節(jié)流保存在不同的 ByteBuffer 中,這些 ByteBuffer 是不同的內(nèi)存塊,通常叫做 Scatter 機(jī)制。

2.4 SocketChannel 的數(shù)據(jù)寫入

SocketChannel 提供了寫入單片數(shù)據(jù)的方法,聲明如下:

public abstract int write(ByteBuffer src) throws IOException

其實,單片數(shù)據(jù)的 write 方法是重寫了 java.nio.channels.WritableByteChannel 中的 write 方法。write 方法是從 ByteBuffer 讀取數(shù)據(jù),寫入 I/O 設(shè)備中,為此調(diào)用者必須將要寫出去的數(shù)據(jù)保存到 ByteBuffer 中。返回值是寫入的字節(jié)數(shù)、0、或者 -1。如果是阻塞式 Channel,write 返回請求寫入的字節(jié)數(shù) 或者 -1;如果是非阻塞式 write 可能會返回 0。

SocketChannel 提供了寫入多片數(shù)據(jù)的方法,聲明如下:

public final long write(ByteBuffer[] dsts) throws IOException
public final long write(ByteBuffer[] dsts, int offset, int length) throws IOException

多片數(shù)據(jù)的 write 方法是重寫了 java.nio.channels.GatheringByteChannel 中的 write 方法。多片數(shù)據(jù) write 方法的返回值和單片數(shù)據(jù) write 方法的返回值具有相同的含義。多片數(shù)據(jù)的 write 方法,其實是將保存在不同的 ByteBuffer 中字節(jié)流寫入 TCP Socket,這些 ByteBuffer 是不同的內(nèi)存塊,通常叫做 Gathering 機(jī)制。

2.5 SocketChannel 的關(guān)閉

SocketChannel 覆寫了 java.nio.channels.Channel 中的 close 方法,完成 TCP 連接的關(guān)閉。方法聲明如下:

public void close() throws IOException

3. ServerSocketChannel 介紹

ServerSocketChannel 用于 TCP 創(chuàng)建服務(wù)器,監(jiān)聽客戶端的連接請求。ServerSocketChannel 也沒有提供 public 的構(gòu)造方法,創(chuàng)建 ServerSocketChannel 的實例,需要調(diào)用它的工廠方法 open。聲明如下:

public static ServerSocketChannel open() throws IOException

ServerSocketChannel 提供了 bind 方法,用于綁定監(jiān)聽的 IP 地址和端口。聲明如下:

public final ServerSocketChannel bind(SocketAddress local) throws IOException
public abstract ServerSocketChannel bind(SocketAddress local, int backlog) throws IOException;

ServerSocketChannel 提供了 accept 方法,接收新的客戶端請求,返回值是 SocketChannel 類型的對象,表示一個新的 TCP 連接。

public abstract SocketChannel accept() throws IOException;

通過 ServerSocketChannel 創(chuàng)建一個 TCP 服務(wù)器,一般需要如下幾個步驟:

try {
    Selector selector = Selector.open();
    ServerSocketChannel serverChannel = ServerSocketChannel.open();
    // 綁定監(jiān)聽的 socket 地址,監(jiān)聽 any_addr
    serverChannel.socket().bind(new InetSocketAddress(PORT));
    // 設(shè)置 SO_REUSEADDR 選項,作為服務(wù)器,這是基本的要求
    serverChannel.socket().setReuseAddress(true);
    // 設(shè)置非阻塞模式,作為服務(wù)器,也是基本要求
    serverChannel.configureBlocking(false);
    // 注冊 accept 事件
    serverChannel.register(selector, SelectionKey.OP_ACCEPT, serverChannel);
} catch (IOException e) {
    e.printStackTrace();
}

后續(xù)的邏輯就是通過 Selector 的 select 方法監(jiān)聽 I/O 事件。然后通過 SocketChannel 的 read 和 write 方法進(jìn)行數(shù)據(jù)讀寫。

4. 小結(jié)

本小節(jié)重點是介紹了 SocketChannel 和 ServerSocketChannel 兩個類提供的重點 API。關(guān)于這兩個類的具體應(yīng)用示例,已經(jīng)在前面的小節(jié)展示,可以參考。