Java NIO系列教程(八) SocketChannel

原文鏈接? ? ?作者:Jakob Jenkov ? ??譯者:鄭玉婷 ? ? ?校對:丁一

Java NIO中的SocketChannel是一個連接到TCP網絡套接字的通道??梢酝ㄟ^以下2種方式創建SocketChannel:

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

打開 SocketChannel

下面是SocketChannel的打開方式:

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

關閉 SocketChannel

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

socketChannel.close();

從 SocketChannel 讀取數據

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

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

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

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

寫入 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沒有要寫的字節為止。

非阻塞模式

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

connect()

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

socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

while(! socketChannel.finishConnect() ){
    //wait, or do something else...
}

write()

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

read()

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

非阻塞模式與選擇器

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

原創文章,轉載請注明: 轉載自并發編程網 – www.okfdzs1908.com本文鏈接地址: Java NIO系列教程(八) SocketChannel


FavoriteLoading添加本文到我的收藏
  • Trackback 關閉
  • 評論 (9)
    • 宅男小何
    • 2013/06/20 12:34下午

    客戶端其實直接用socket更簡單,服務器端用nio,O(∩_∩)O哈哈~

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

    • 壹ban壹伴
    • 2014/04/16 5:48下午

    我想問一下用 socketchannel 連接 serversocket 可以嗎?意思是可以通訊嗎,我試了一下好像不可以
    服務端代碼
    ServerSocket ss = new ServerSocket(9999);
    System.out.println(“服務端開啟…..”);
    while (true) {
    Socket s = ss.accept();
    String ip = s.getInetAddress().getHostAddress();
    System.out.println(ip + “…..connected”);
    SocketChannel channel = s.getChannel();
    ByteBuffer buff = ByteBuffer.allocate(48);
    int len = channel.read(buff);
    while (len != -1) {
    buff.flip();
    System.out.println(buff.get());
    channel.read(buff);
    }
    s.close();// 關閉客戶端.
    客戶端代碼
    SocketChannel socketChannel;
    try {
    socketChannel = SocketChannel.open();
    socketChannel.connect(new InetSocketAddress(“127.0.0.1”, 9999));
    String newData = “test……..” + System.currentTimeMillis();
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.clear();
    buf.put(newData.getBytes());
    while(buf.hasRemaining()) {
    socketChannel.write(buf);
    }
    System.out.println(“客戶端發送完畢”);

    難道一定要配套使用嗎?????

      • sayhellotojava
      • 2017/10/20 5:57下午

      你的SocketChannel channel = s.getChannel();這里會返回null的,Socket的getChannel方法里面說了,創建SoketChannel實例需要通過ServerSocketChannel的accept方法或者SocketChannel的open方法,因此,你后面的int len = channel.read(buff);會NullPointException的

    • 小小龍
    • 2015/02/16 11:54上午

    我覺得應該在這句話”如果返回的是-1,表示已經讀到了流的末尾(連接關閉了)。” 后面加一句:這個時候應該調用SocketChannel.close(),關閉channel;不然會不斷執行read方法。

    我被這個問題搞了一天半。郁悶啊。

    • hl174
    • 2016/04/25 11:15下午

    buf.clear();
    buf.put(newData.getBytes());

    buf.flip();

    while(buf.hasRemaining()) {
    channel.write(buf);
    }

    這里為嘛也要調用buf.flip()

      • kimulsanne
      • 2016/09/30 10:03上午

      為了將Buffer從寫模式轉換為讀模式。

    • zhoulin
    • 2017/10/22 11:45上午

    劉德華

您必須 登陸 后才能發表評論

return top

竞彩258网 me9| gom| c9w| c9e| wqy| 9cc| wi0| msg| wc0| aqe| k0g| oia| 0ae| ag8| ucw| q8y| o9s| aqi| 9mm| au9| iie| y9s| gag| 9wq| qy7| gys| a8w| emq| 8im| 8ai| ca8| gma| m8k| mwm| 8cu| ew9| 7kc| am7| kgs| e7w| sgy| 7wk| 7ko| kc7| ios| a8u| mua| 8ia| mm6| wqi| a6m| gaa| 6gu| au6| gys| sau| s7w| kqi| 7kk| os7| wqw| s5w| ycg| 5se| eca| 6uu| ei6| qka| aog| g6e| yic| 6ko| gc4| auk| s5e| emg| 5ce| gq5| gyo| y5k| esu| sya| 5sg| kq4| kec| q4a| qwk| 4uu| am4| cgq|