SocketChannel和ServerSocketChannel


SocketChannel

1. SocketChannel概述

Java NIO中的SocketChannel是一個連接到TCP網絡套接字的通道。可以通過以下2種方式創建SocketChannel:

  1. 打開一個SocketChannel並連接到互聯網上的某台服務器。
  2. 一個新連接到達ServerSocketChannel時,會創建一個SocketChannel。

 

1.1 打開 SocketChannel

下面是SocketChannel的打開方式:

 

SocketChannel socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

 

1.2 關閉 SocketChannel

當用完SocketChannel之后調用SocketChannel.close()關閉SocketChannel:

 

socketChannel.close();

 

1.3 SocketChannel讀取數據

要從SocketChannel中讀取數據,調用一個read()的方法之一。以下是例子:

 

ByteBuffer buf = ByteBuffer.allocate(48); int bytesRead = socketChannel.read(buf);

 

首先,分配一個Buffer。從SocketChannel讀取到的數據將會放到這個Buffer中。

然后,調用SocketChannel.read()。該方法將數據從SocketChannel 讀到Buffer中。read()方法返回的int值表示讀了多少字節進Buffer里。如果返回的是-1,表示已經讀到了流的末尾(連接關閉了)。

1.4 SocketChannel寫入數據

寫數據到SocketChannel用的是SocketChannel.write()方法,該方法以一個Buffer作為參數。示例如下:

 

String newData = "New String to write to file..." + System.currentTimeMillis();  ByteBuffer buf = ByteBuffer.allocate(48); buf.clear(); buf.put(newData.getBytes()); buf.flip(); while(buf.hasRemaining()) {  channel.write(buf); }

 

注意SocketChannel.write()方法的調用是在一個while循環中的。Write()方法無法保證能寫多少字節到SocketChannel。所以,我們重復調用write()直到Buffer沒有要寫的字節為止。

2. SocketChannel非阻塞模式

可以設置 SocketChannel 為非阻塞模式(non-blocking mode).設置之后,就可以在異步模式下調用connect(), read() 和write()了。

2.1 connect()

如果SocketChannel在非阻塞模式下,此時調用connect(),該方法可能在連接建立之前就返回了。為了確定連接是否建立,可以調用finishConnect()的方法。像這樣:

 

socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));  while(! socketChannel.finishConnect() ){  //wait, or do something else... }

 

2.2 write()

非阻塞模式下,write()方法在尚未寫出任何內容時可能就返回了。所以需要在循環中調用write()。前面已經有例子了,這里就不贅述了。

2.3 read()

非阻塞模式下,read()方法在尚未讀取到任何數據時可能就返回了。所以需要關注它的int返回值,它會告訴你讀取了多少字節。

3. SocketChannel非阻塞模式

非阻塞模式與選擇器搭配會工作的更好,通過將一或多個SocketChannel注冊到Selector,可以詢問選擇器哪個通道已經准備好了讀取,寫入等。Selector與SocketChannel的搭配使用會在后面詳講

 

 

ServerSocketChannel

1.ServerSocketChannel概述

Java NIO中的 ServerSocketChannel 是一個可以監聽新進來的TCP連接的通道, 就像標准IO中的ServerSocket一樣。ServerSocketChannel類在 java.nio.channels包中

 

1.1 打開 ServerSocketChannel

通過調用 ServerSocketChannel.open() 方法來打開ServerSocketChannel.如:

 

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

 

1.2 關閉 ServerSocketChannel

通過調用ServerSocketChannel.close() 方法來關閉ServerSocketChannel. 如:

 

serverSocketChannel.close();

1.3 監聽新進來的連接

通過 ServerSocketChannel.accept() 方法監聽新進來的連接。當 accept()方法返回的時候,它返回一個包含新進來的連接的 SocketChannel。因此, accept()方法會一直阻塞到有新連接到達。

通常不會僅僅只監聽一個連接,在while循環中調用 accept()方法. 如下面的例子:

 

while(true){  SocketChannel socketChannel =  serverSocketChannel.accept();   //do something with socketChannel... }

當然,也可以在while循環中使用除了true以外的其它退出准則。

2. ServerSocketChannel非阻塞模式

ServerSocketChannel可以設置成非阻塞模式。在非阻塞模式下,accept() 方法會立刻返回,如果還沒有新進來的連接,返回的將是null。 因此,需要檢查返回的SocketChannel是否是null

 

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false);  while(true){  SocketChannel socketChannel =  serverSocketChannel.accept();   if(socketChannel != null){  //do something with socketChannel...  } }

 

SocketChannel示例

 

如下是一個ServerSocketChannel的示例,注意需要先啟動ServerSocketChannel

 

@Test  public void test2() throws IOException {  ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  serverSocketChannel.socket().bind(new InetSocketAddress(9999));  serverSocketChannel.configureBlocking(false);  ByteBuffer buf = ByteBuffer.allocate(256);  while(true){  SocketChannel socketChannel =  serverSocketChannel.accept();  if(socketChannel != null){  int bytesRead = socketChannel.read(buf);  while(bytesRead>0){  buf.flip();  while(buf.hasRemaining()){  System.out.print((char)buf.get());  }  System.out.println();  buf.clear();  bytesRead = socketChannel.read(buf);  }  }  }  }

 

如下是一個SocketChannel 的示例

@Test  public void test1() throws IOException, InterruptedException {  SocketChannel socketChannel = SocketChannel.open();  //設置為NIO  socketChannel.configureBlocking(false);  socketChannel.connect(new InetSocketAddress("localhost", 9999));  ByteBuffer buf = ByteBuffer.allocate(256);  if(socketChannel.finishConnect())  {  int i=0;  while(true)  {  TimeUnit.SECONDS.sleep(1);  String info = "I'm "+i+++"-th information from client";  buf.clear();  buf.put(info.getBytes());  buf.flip();  while(buf.hasRemaining()){  socketChannel.write(buf);  }  }  }  }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM