JAVA-NIO之Socket/ServerSocket Channel(詳解)
一、ServerSocketChannel
Java NIO中的 ServerSocketChannel 是一個可以監(jiān)聽新進(jìn)來的TCP連接的通道, 就像標(biāo)準(zhǔn)IO中的ServerSocket一樣。ServerSocketChannel類在 java.nio.channels包中。
打開 ServerSocketChannel
通過調(diào)用 ServerSocketChannel.open() 方法來打開ServerSocketChannel.
關(guān)閉 ServerSocketChannel
通過調(diào)用ServerSocketChannel.close() 方法來關(guān)閉ServerSocketChannel.
監(jiān)聽新進(jìn)來的連接
通過 ServerSocketChannel.accept() 方法監(jiān)聽新進(jìn)來的連接。當(dāng) accept()方法返回的時候,它返回一個包含新進(jìn)來的連接的 SocketChannel。因此, accept()方法會一直阻塞到有新連接到達(dá)。
通常不會僅僅只監(jiān)聽一個連接,在while循環(huán)中調(diào)用 accept()方法.
當(dāng)然,也可以在while循環(huán)中使用除了true以外的其它退出準(zhǔn)則。
非阻塞模式
ServerSocketChannel可以設(shè)置成非阻塞模式。在非阻塞模式下,accept() 方法會立刻返回,如果還沒有新進(jìn)來的連接,返回的將是null。 因此,需要檢查返回的SocketChannel是否是null.如:
/** * socket server channel */ @Test public void text2() throws IOException { ServerSocketChannel channel = ServerSocketChannel.open(); //新建channel channel.socket().bind(new InetSocketAddress(9999)); //監(jiān)聽端口 channel.configureBlocking(true); //設(shè)置阻塞 while (true) { SocketChannel accept = channel.accept(); //設(shè)置為阻塞,則此方法阻塞,直到有連接 //如果設(shè)置為非阻塞,需要在這里判斷 accept == null? ByteBuffer byteBuffer = ByteBuffer.allocate(1024); accept.read(byteBuffer); byteBuffer.flip(); //反轉(zhuǎn) while (byteBuffer.hasRemaining()) { //判斷 System.err.println((char)byteBuffer.get()); //輸出 } } }
二、SocketChannel
Java NIO中的SocketChannel是一個連接到TCP網(wǎng)絡(luò)套接字的通道。可以通過以下2種方式創(chuàng)建SocketChannel:
打開一個SocketChannel并連接到互聯(lián)網(wǎng)上的某臺服務(wù)器。
一個新連接到達(dá)ServerSocketChannel時,會創(chuàng)建一個SocketChannel。
打開 SocketChannel
下面是SocketChannel的打開方式:
關(guān)閉 SocketChannel
當(dāng)用完SocketChannel之后調(diào)用SocketChannel.close()關(guān)閉SocketChannel:
從 SocketChannel 讀取數(shù)據(jù)
要從SocketChannel中讀取數(shù)據(jù),調(diào)用一個read()的方法之一。
首先,分配一個Buffer。從SocketChannel讀取到的數(shù)據(jù)將會放到這個Buffer中。
然后,調(diào)用SocketChannel.read()。該方法將數(shù)據(jù)從SocketChannel 讀到Buffer中。read()方法返回的int值表示讀了多少字節(jié)進(jìn)Buffer里。如果返回的是-1,表示已經(jīng)讀到了流的末尾(連接關(guān)閉了)。
寫入 SocketChannel
寫數(shù)據(jù)到SocketChannel用的是SocketChannel.write()方法,該方法以一個Buffer作為參數(shù)。
注意SocketChannel.write()方法的調(diào)用是在一個while循環(huán)中的。Write()方法無法保證能寫多少字節(jié)到SocketChannel。所以,我們重復(fù)調(diào)用write()直到Buffer沒有要寫的字節(jié)為止。
非阻塞模式
可以設(shè)置 SocketChannel 為非阻塞模式(non-blocking mode).設(shè)置之后,就可以在異步模式下調(diào)用connect(), read() 和write()了。
connect()
如果SocketChannel在非阻塞模式下,此時調(diào)用connect(),該方法可能在連接建立之前就返回了。為了確定連接是否建立,可以調(diào)用finishConnect()的方法。
write()
非阻塞模式下,write()方法在尚未寫出任何內(nèi)容時可能就返回了。所以需要在循環(huán)中調(diào)用write()。前面已經(jīng)有例子了,這里就不贅述了。
read()
非阻塞模式下,read()方法在尚未讀取到任何數(shù)據(jù)時可能就返回了。所以需要關(guān)注它的int返回值,它會告訴你讀取了多少字節(jié)。
非阻塞模式與選擇器
非阻塞模式與選擇器搭配會工作的更好,通過將一或多個SocketChannel注冊到Selector,可以詢問選擇器哪個通道已經(jīng)準(zhǔn)備好了讀取,寫入等。Selector與SocketChannel的搭配使用會在后面詳講。
/** * socket channel */ @Test public void test3() throws IOException { SocketChannel channel = SocketChannel.open(); //新建服務(wù)端 channel.connect(new InetSocketAddress("127.0.0.1",9999)); //連接服務(wù)端地址 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); //緩沖區(qū) byteBuffer.put("123".getBytes()); byteBuffer.flip(); //反轉(zhuǎn) while (byteBuffer.hasRemaining()) { //判斷 channel.write(byteBuffer); } }
以上這篇JAVA-NIO之Socket/ServerSocket Channel(詳解)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot項(xiàng)目實(shí)現(xiàn)MyBatis流式查詢的教程詳解
這篇文章主要介紹了SpringBoot項(xiàng)目如何實(shí)現(xiàn)MyBatis的流式查詢,mybatis的流式查詢,有點(diǎn)冷門,實(shí)際用的場景比較少,但是在某些特殊場景下,卻是十分有效的一個方法,感興趣的同學(xué)可以參考一下2023-06-06SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過程詳細(xì)分析
這篇文章主要介紹了SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過程,單點(diǎn)登錄英文全稱Single?Sign?On,簡稱就是SSO。它的解釋是:在多個應(yīng)用系統(tǒng)中,只需要登錄一次,就可以訪問其他相互信任的應(yīng)用系統(tǒng)2022-12-12Maven項(xiàng)目繼承實(shí)現(xiàn)過程圖解
這篇文章主要介紹了Maven項(xiàng)目繼承實(shí)現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-08-08java獲取新insert數(shù)據(jù)自增id的實(shí)現(xiàn)方法
這篇文章主要介紹了java獲取新insert數(shù)據(jù)自增id的實(shí)現(xiàn)方法,在具體生成id的時候,我們的操作順序一般是:先在主表中插入記錄,然后獲得自動生成的id,以它為基礎(chǔ)插入從表的記錄,需要的朋友可以參考下2019-06-06