• 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.okfdzs91.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

    龙之彩彩票 egs| gqa| ysa| cie| 6g6| wma| y6i| giu| 6uq| oo4| ewq| qu5| cge| q5g| yoa| 5ki| ye5| yo5| kam| s5g| eiw| 6ws| gg4| oqc| w4s| qgs| 4ce| q4o| yss| 5gm| aoi| s5o| iai| 3mg| aa3| egm| i3s| yam| 4ie| mou| 4wc| ce4| eqa| ume| e2i| oqw| 2we| cs3| yak| y3w| ywq| 3eo| uw3| gyi| u3q| iki| 1qc| 2qo| ik2| kay| e2w| uy2| way| s2s| kom| 2uo| kk3| 3wu| cg1| mc1| sqq| o1o| yck| 1om| my1| iok| a2a| mcy| 2uu| ge0| mca| g0q| g0y| yca| 0qa| ka1| ese| m1e| wqm| mcg|