欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報邀請碼778899分享:網(wǎng)絡(luò) NIO基礎(chǔ)

柚子快報邀請碼778899分享:網(wǎng)絡(luò) NIO基礎(chǔ)

http://yzkb.51969.com/

文章目錄

NIO基礎(chǔ)1. 三大組件1.1 Channel1.2 Buffer1.3 Selector

2. ByteBuffer2.1 使用方式2.2 常見方法2.3 解決黏包問題

3. 網(wǎng)絡(luò)編程3.1 阻塞3.2 非阻塞3.3 多路復(fù)用3.4 利用多線程優(yōu)化

NIO基礎(chǔ)

1. 三大組件

1.1 Channel

channel 有一點類似于 stream,它就是讀寫數(shù)據(jù)的雙向通道,可以從 channel 將數(shù)據(jù)讀入 buffer,也可以將 buffer 的數(shù)據(jù)寫入 channel,而之前的 stream 要么是輸入,要么是輸出,channel 比 stream 更為底層

#mermaid-svg-DR2N3ForJ1jDTJdz {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .error-icon{fill:#552222;}#mermaid-svg-DR2N3ForJ1jDTJdz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DR2N3ForJ1jDTJdz .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-DR2N3ForJ1jDTJdz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DR2N3ForJ1jDTJdz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DR2N3ForJ1jDTJdz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DR2N3ForJ1jDTJdz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DR2N3ForJ1jDTJdz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DR2N3ForJ1jDTJdz .marker.cross{stroke:#333333;}#mermaid-svg-DR2N3ForJ1jDTJdz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DR2N3ForJ1jDTJdz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .cluster-label text{fill:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .cluster-label span{color:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .label text,#mermaid-svg-DR2N3ForJ1jDTJdz span{fill:#333;color:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .node rect,#mermaid-svg-DR2N3ForJ1jDTJdz .node circle,#mermaid-svg-DR2N3ForJ1jDTJdz .node ellipse,#mermaid-svg-DR2N3ForJ1jDTJdz .node polygon,#mermaid-svg-DR2N3ForJ1jDTJdz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DR2N3ForJ1jDTJdz .node .label{text-align:center;}#mermaid-svg-DR2N3ForJ1jDTJdz .node.clickable{cursor:pointer;}#mermaid-svg-DR2N3ForJ1jDTJdz .arrowheadPath{fill:#333333;}#mermaid-svg-DR2N3ForJ1jDTJdz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DR2N3ForJ1jDTJdz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DR2N3ForJ1jDTJdz .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-DR2N3ForJ1jDTJdz .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-DR2N3ForJ1jDTJdz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DR2N3ForJ1jDTJdz .cluster text{fill:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz .cluster span{color:#333;}#mermaid-svg-DR2N3ForJ1jDTJdz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DR2N3ForJ1jDTJdz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

channel

buffer

常見的 Channel 有:

FileChannelDatagramChannelSocketChannelServerSocketChannel

1.2 Buffer

Buffer 是一塊可以寫入數(shù)據(jù),然后可以從中讀取數(shù)據(jù)的內(nèi)存塊。

它與數(shù)組類似,但是提供了對數(shù)據(jù)的結(jié)構(gòu)化訪問,并且可以跟蹤已經(jīng)讀寫了多少數(shù)據(jù)。

常見的 buffer 有:

ByteBuffer

MappedByteBufferDirectByteBufferHeapByteBuffer ShortBufferIntBufferLongBufferFloatBufferDoubleBufferCharBuffer

1.3 Selector

Selector 是 NIO 中實現(xiàn)多路復(fù)用的關(guān)鍵組件,允許單個線程管理多個 Channel。

Selector 能夠監(jiān)控多個注冊到它的 Channel 上是否有事件發(fā)生(如連接建立、數(shù)據(jù)到達(dá)等)。這樣,一個單獨的線程可以通過輪詢 Selector 來判斷一組 Channel 是否有就緒狀態(tài)的事件,從而只需要少量的線程就能處理大量的客戶端請求。

使用 Selector 可以顯著減少系統(tǒng)資源的開銷,特別適用于需要同時處理大量網(wǎng)絡(luò)連接的情況。

#mermaid-svg-nsG1OxHPZTfhJS8Y {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .error-icon{fill:#552222;}#mermaid-svg-nsG1OxHPZTfhJS8Y .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-nsG1OxHPZTfhJS8Y .marker{fill:#333333;stroke:#333333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .marker.cross{stroke:#333333;}#mermaid-svg-nsG1OxHPZTfhJS8Y svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .cluster-label text{fill:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .cluster-label span{color:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .label text,#mermaid-svg-nsG1OxHPZTfhJS8Y span{fill:#333;color:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .node rect,#mermaid-svg-nsG1OxHPZTfhJS8Y .node circle,#mermaid-svg-nsG1OxHPZTfhJS8Y .node ellipse,#mermaid-svg-nsG1OxHPZTfhJS8Y .node polygon,#mermaid-svg-nsG1OxHPZTfhJS8Y .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .node .label{text-align:center;}#mermaid-svg-nsG1OxHPZTfhJS8Y .node.clickable{cursor:pointer;}#mermaid-svg-nsG1OxHPZTfhJS8Y .arrowheadPath{fill:#333333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-nsG1OxHPZTfhJS8Y .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-nsG1OxHPZTfhJS8Y .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-nsG1OxHPZTfhJS8Y .cluster text{fill:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y .cluster span{color:#333;}#mermaid-svg-nsG1OxHPZTfhJS8Y div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-nsG1OxHPZTfhJS8Y :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}

selector

thread

channel

channel

channel

2. ByteBuffer

2.1 使用方式

向 buffer 寫入數(shù)據(jù),例如調(diào)用 channel.read(buffer)調(diào)用 flip() 切換至讀模式從 buffer 讀取數(shù)據(jù),例如調(diào)用 buffer.get()調(diào)用 clear() 或 compact() 切換至寫模式重復(fù) 1~4 步驟

示例:

@Slf4j

public class BufferDemo {

public static void main(String[] args) {

try (RandomAccessFile file =

new RandomAccessFile("test.txt", "rw")){

ByteBuffer buffer = ByteBuffer.allocate(10);

FileChannel channel = file.getChannel();

while (true){

int read = channel.read(buffer);

if(read == -1)break;

buffer.flip();

while(buffer.hasRemaining()){

log.info("讀取到:{}",(char)buffer.get());

}

buffer.clear();

}

} catch (Exception e) {

throw new RuntimeException(e);

}

}

}

2.2 常見方法

分配空間:

Bytebuffer buf = ByteBuffer.allocate(16);

寫入數(shù)據(jù)有兩種辦法:

調(diào)用 channel 的 read 方法調(diào)用 buffer 自己的 put 方法

int readBytes = channel.read(buf);

buf.put((byte)127);

讀取數(shù)據(jù)同樣有兩種辦法:

調(diào)用 channel 的 write 方法調(diào)用 buffer 自己的 get 方法

int writeBytes = channel.write(buf);

byte b = buf.get();

get 方法會讓 position 讀指針向后走,如果想重復(fù)讀取數(shù)據(jù)

可以調(diào)用 rewind 方法將 position 重新置為 0或者調(diào)用 get(int i) 方法獲取索引 i 的內(nèi)容,它不會移動讀指針

mark 和 reset:

mark 是在讀取時,做一個標(biāo)記,即使 position 改變,只要調(diào)用 reset 就能回到 mark 的位置

字符串與 ByteBuffer 互轉(zhuǎn):

ByteBuffer buffer1 = StandardCharsets.UTF_8.encode("你好");

ByteBuffer buffer2 = Charset.forName("utf-8").encode("你好");

debug(buffer1);

debug(buffer2);

CharBuffer buffer3 = StandardCharsets.UTF_8.decode(buffer1);

System.out.println(buffer3.getClass());

System.out.println(buffer3.toString());

2.3 解決黏包問題

將錯亂的數(shù)據(jù)恢復(fù)成原始的按 \n 分隔的數(shù)據(jù):

public static void main(String[] args) {

ByteBuffer source = ByteBuffer.allocate(32);

source.put("Hello,world\nI'm zhangsan\nHo".getBytes());

split(source);

source.put("w are you?\nhaha!\n".getBytes());

split(source);

}

private static void split(ByteBuffer source) {

source.flip();

int oldLimit = source.limit();

for (int i = 0; i < oldLimit; i++) {

if (source.get(i) == '\n') {

System.out.println(i);

ByteBuffer target = ByteBuffer.allocate(i + 1 - source.position());

// 0 ~ limit

source.limit(i + 1);

target.put(source); // 從source 讀,向 target 寫

debugAll(target);

source.limit(oldLimit);

}

}

source.compact();

}

3. 網(wǎng)絡(luò)編程

3.1 阻塞

阻塞模式下,相關(guān)方法都會導(dǎo)致線程暫停

ServerSocketChannel.accept 會在沒有連接建立時讓線程暫停SocketChannel.read 會在沒有數(shù)據(jù)可讀時讓線程暫停阻塞的表現(xiàn)其實就是線程暫停了,暫停期間不會占用 cpu,但線程相當(dāng)于閑置

// 使用 nio 來理解阻塞模式, 單線程

// 0. ByteBuffer

ByteBuffer buffer = ByteBuffer.allocate(16);

// 1. 創(chuàng)建了服務(wù)器

ServerSocketChannel ssc = ServerSocketChannel.open();

// 2. 綁定監(jiān)聽端口

ssc.bind(new InetSocketAddress(8080));

// 3. 連接集合

List channels = new ArrayList<>();

while (true) {

// 4. accept 建立與客戶端連接, SocketChannel 用來與客戶端之間通信

log.debug("connecting...");

SocketChannel sc = ssc.accept(); // 阻塞方法,線程停止運行

log.debug("connected... {}", sc);

channels.add(sc);

for (SocketChannel channel : channels) {

// 5. 接收客戶端發(fā)送的數(shù)據(jù)

log.debug("before read... {}", channel);

channel.read(buffer); // 阻塞方法,線程停止運行

buffer.flip();

debugRead(buffer);

buffer.clear();

log.debug("after read...{}", channel);

}

}

3.2 非阻塞

非阻塞模式下,相關(guān)方法都會不會讓線程暫停

在 ServerSocketChannel.accept 在沒有連接建立時,會返回 null,繼續(xù)運行SocketChannel.read 在沒有數(shù)據(jù)可讀時,會返回 0,但線程不必阻塞,可以去執(zhí)行其它 SocketChannel 的 read 或是去執(zhí)行 ServerSocketChannel.accept寫數(shù)據(jù)時,線程只是等待數(shù)據(jù)寫入 Channel 即可,無需等 Channel 通過網(wǎng)絡(luò)把數(shù)據(jù)發(fā)送出去 但非阻塞模式下,即使沒有連接建立,和可讀數(shù)據(jù),線程仍然在不斷運行,白白浪費了 cpu

// 使用 nio 來理解非阻塞模式, 單線程

// 0. ByteBuffer

ByteBuffer buffer = ByteBuffer.allocate(16);

// 1. 創(chuàng)建了服務(wù)器

ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.configureBlocking(false); // 非阻塞模式

// 2. 綁定監(jiān)聽端口

ssc.bind(new InetSocketAddress(8080));

// 3. 連接集合

List channels = new ArrayList<>();

while (true) {

// 4. accept 建立與客戶端連接, SocketChannel 用來與客戶端之間通信

SocketChannel sc = ssc.accept(); // 非阻塞,線程還會繼續(xù)運行,如果沒有連接建立,但sc是null

if (sc != null) {

log.debug("connected... {}", sc);

sc.configureBlocking(false); // 非阻塞模式

channels.add(sc);

}

for (SocketChannel channel : channels) {

// 5. 接收客戶端發(fā)送的數(shù)據(jù)

int read = channel.read(buffer);// 非阻塞,線程仍然會繼續(xù)運行,如果沒有讀到數(shù)據(jù),read 返回 0

if (read > 0) {

buffer.flip();

debugRead(buffer);

buffer.clear();

log.debug("after read...{}", channel);

}

}

}

3.3 多路復(fù)用

單線程可以配合 Selector 完成對多個 Channel 可讀寫事件的監(jiān)控,這稱之為多路復(fù)用

多路復(fù)用僅針對網(wǎng)絡(luò) IO、普通文件 IO 沒法利用多路復(fù)用如果不用 Selector 的非阻塞模式,線程大部分時間都在做無用功,而 Selector 能夠保證

有可連接事件時才去連接有可讀事件才去讀取有可寫事件才去寫入

好處

一個線程配合 selector 就可以監(jiān)控多個 channel 的事件,事件發(fā)生線程才去處理。避免非阻塞模式下所做無用功讓這個線程能夠被充分利用節(jié)約了線程的數(shù)量減少了線程上下文切換

處理read事件服務(wù)器代碼:

public static void main(String[] args) throws IOException {

// 1. 創(chuàng)建 selector, 管理多個 channel

Selector selector = Selector.open();

ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.configureBlocking(false);

// 2. 建立 selector 和 channel 的聯(lián)系(注冊)

// SelectionKey 就是將來事件發(fā)生后,通過它可以知道事件和哪個channel的事件

SelectionKey sscKey = ssc.register(selector, 0, null);

// key 只關(guān)注 accept 事件

sscKey.interestOps(SelectionKey.OP_ACCEPT);

log.debug("sscKey:{}", sscKey);

ssc.bind(new InetSocketAddress(8080));

while (true) {

// 3. select 方法, 沒有事件發(fā)生,線程阻塞,有事件,線程才會恢復(fù)運行

// select 在事件未處理時,它不會阻塞, 事件發(fā)生后要么處理,要么取消,不能置之不理

selector.select();

// 4. 處理事件, selectedKeys 內(nèi)部包含了所有發(fā)生的事件

Iterator iter = selector.selectedKeys().iterator(); // accept, read

while (iter.hasNext()) {

SelectionKey key = iter.next();

// 處理key 時,要從 selectedKeys 集合中刪除,否則下次處理就會有問題

iter.remove();

log.debug("key: {}", key);

// 5. 區(qū)分事件類型

if (key.isAcceptable()) { // 如果是 accept

ServerSocketChannel channel = (ServerSocketChannel) key.channel();

SocketChannel sc = channel.accept();

sc.configureBlocking(false);

ByteBuffer buffer = ByteBuffer.allocate(16); // attachment

// 將一個 byteBuffer 作為附件關(guān)聯(lián)到 selectionKey 上

SelectionKey scKey = sc.register(selector, 0, buffer);

scKey.interestOps(SelectionKey.OP_READ);

log.debug("{}", sc);

log.debug("scKey:{}", scKey);

} else if (key.isReadable()) { // 如果是 read

try {

SocketChannel channel = (SocketChannel) key.channel(); // 拿到觸發(fā)事件的channel

// 獲取 selectionKey 上關(guān)聯(lián)的附件

ByteBuffer buffer = (ByteBuffer) key.attachment();

int read = channel.read(buffer); // 如果是正常斷開,read 的方法的返回值是 -1

if(read == -1) {

key.cancel();

} else {

split(buffer);

// 需要擴(kuò)容

if (buffer.position() == buffer.limit()) {

ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2);

buffer.flip();

newBuffer.put(buffer); // 0123456789abcdef3333\n

key.attach(newBuffer);

}

}

} catch (IOException e) {

e.printStackTrace();

key.cancel(); // 因為客戶端斷開了,因此需要將 key 取消(從 selector 的 keys 集合中真正刪除 key)

}

}

}

}

}

處理write時間服務(wù)端代碼:

public static void main(String[] args) throws IOException {

Selector selector = Selector.open();

ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.bind(new InetSocketAddress(8080));

ssc.configureBlocking(false);

ssc.register(selector,SelectionKey.OP_ACCEPT);

while(true){

selector.select();

Iterator iterator = selector.selectedKeys().iterator();

while(iterator.hasNext()){

SelectionKey key = iterator.next();

try {

if(key.isAcceptable()){

SocketChannel sc = ssc.accept();

sc.configureBlocking(false);

StringBuilder sb = new StringBuilder();

for(int i=0;i<10000;i++){

sb.append("a");

}

ByteBuffer buffer = Charset.defaultCharset().encode(sb.toString());

sc.write(buffer);

if(buffer.hasRemaining()){

sc.register(selector,SelectionKey.OP_WRITE,buffer);

}

}else if(key.isWritable()){

ByteBuffer attachment = (ByteBuffer)key.attachment();

SocketChannel sc = (SocketChannel)key.channel();

sc.write(attachment);

if(!attachment.hasRemaining()){

key.cancel();

}

}

} catch (IOException e) {

e.printStackTrace();

key.cancel();

}

}

}

}

3.4 利用多線程優(yōu)化

public class ChannelDemo7 {

public static void main(String[] args) throws IOException {

new BossEventLoop().register();

}

@Slf4j

static class BossEventLoop implements Runnable {

private Selector boss;

private WorkerEventLoop[] workers;

private volatile boolean start = false;

AtomicInteger index = new AtomicInteger();

public void register() throws IOException {

if (!start) {

ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.bind(new InetSocketAddress(8080));

ssc.configureBlocking(false);

boss = Selector.open();

SelectionKey ssckey = ssc.register(boss, 0, null);

ssckey.interestOps(SelectionKey.OP_ACCEPT);

workers = initEventLoops();

new Thread(this, "boss").start();

log.debug("boss start...");

start = true;

}

}

public WorkerEventLoop[] initEventLoops() {

// EventLoop[] eventLoops = new EventLoop[Runtime.getRuntime().availableProcessors()];

WorkerEventLoop[] workerEventLoops = new WorkerEventLoop[2];

for (int i = 0; i < workerEventLoops.length; i++) {

workerEventLoops[i] = new WorkerEventLoop(i);

}

return workerEventLoops;

}

@Override

public void run() {

while (true) {

try {

boss.select();

Iterator iter = boss.selectedKeys().iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

iter.remove();

if (key.isAcceptable()) {

ServerSocketChannel c = (ServerSocketChannel) key.channel();

SocketChannel sc = c.accept();

sc.configureBlocking(false);

log.debug("{} connected", sc.getRemoteAddress());

workers[index.getAndIncrement() % workers.length].register(sc);

}

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

@Slf4j

static class WorkerEventLoop implements Runnable {

private Selector worker;

private volatile boolean start = false;

private int index;

private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue<>();

public WorkerEventLoop(int index) {

this.index = index;

}

public void register(SocketChannel sc) throws IOException {

if (!start) {

worker = Selector.open();

new Thread(this, "worker-" + index).start();

start = true;

}

tasks.add(() -> {

try {

SelectionKey sckey = sc.register(worker, 0, null);

sckey.interestOps(SelectionKey.OP_READ);

worker.selectNow();

} catch (IOException e) {

e.printStackTrace();

}

});

worker.wakeup();

}

@Override

public void run() {

while (true) {

try {

worker.select();

Runnable task = tasks.poll();

if (task != null) {

task.run();

}

Set keys = worker.selectedKeys();

Iterator iter = keys.iterator();

while (iter.hasNext()) {

SelectionKey key = iter.next();

if (key.isReadable()) {

SocketChannel sc = (SocketChannel) key.channel();

ByteBuffer buffer = ByteBuffer.allocate(128);

try {

int read = sc.read(buffer);

if (read == -1) {

key.cancel();

sc.close();

} else {

buffer.flip();

log.debug("{} message:", sc.getRemoteAddress());

debugAll(buffer);

}

} catch (IOException e) {

e.printStackTrace();

key.cancel();

sc.close();

}

}

iter.remove();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

}

柚子快報邀請碼778899分享:網(wǎng)絡(luò) NIO基礎(chǔ)

http://yzkb.51969.com/

文章鏈接

評論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。

轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19548712.html

發(fā)布評論

您暫未設(shè)置收款碼

請在主題配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄