java架構《Socket網絡編程基礎篇》


   本章主要介紹Socket的基本概念,傳統的同步阻塞式I/O編程,偽異步IO實現,學習NIO的同步非阻塞編程和NIO2.0(AIO)異步非阻塞編程。

  

目前為止,Java共支持3種網絡編程模型:BIO、NIO、AIO:


Java BIO : 同步並阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。
Java NIO : 同步非阻塞,服務器實現模式為一個請求一個線程,即客戶端發送的連接請求都會注冊到多路復用器上,多路復用器輪詢到連接有I/O請求時才啟動一個線程進行處理。
Java AIO(NIO.2) : 異步非阻塞,服務器實現模式為一個有效請求一個線程,客戶端的I/O請求都是由OS先完成了再通知服務器應用去啟動線程進行處理。

     BIO、NIO、AIO適用場景分析:


BIO方式適用於連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,並發局限於應用中,JDK1.4以前的唯一選擇,但程序直觀簡單易理解。
NIO方式適用於連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,並發局限於應用中,編程比較復雜,JDK1.4開始支持。
AIO方式使用於連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用OS參與並發操作,編程比較復雜,JDK7開始支持。
 

 

  一:基本概念

        Socket又被稱為 "套接字" ,應用程序通常都是通過 "套接字" 向網絡發出請求和接收請求。Socket和serverSocket類位於java.net包中。ServerSocket用於(Server)服務端,Socket用於

      (Client)客戶端。當服務端和客戶端建立連接后。兩端都會產生一個Socket實例,並且是平等的。不管是Socket還是ServerSocket。都是通過操作SocketImpl和其子類完成相關功能。


 

    

    連接過程四步驟: 1:服務器監聽  2:客戶端請求   3:服務端連接確認   4:客戶端連接確認

 

  二:傳統同步阻塞IO實現

           服務端ServerSocket:

             

1               final static int PROT = 8765;
2 
3               ServerSocket server = null;
4 
5               server = new ServerSocket(PROT);
6 
7               Socket socket = server.accept();  //進行阻塞
8 
9               new Thread(new ServerHandler(socket)).start();  //服務端運行,等待客戶端連接

 

 

         客戶端Socket:

              

1               final static String ADDRESS = "127.0.0.1";
2 
3               final static int PORT = 8765;
4 
5                Socket socket = null;
6 
7               socket = new Socket(ADDRESS, PORT);  //進行連接

 

      

          服務端處理器ServerHandler:

          

 1              // 實現Runnable
 2 
 3                 private Socket socket ;
 4 
 5                 public ServerHandler(Socket socket){
 6                   this.socket = socket;
 7                 }
 8 
 9               //重寫run方法:   
10 
11                 @Override
12                 public void run() {
13                 BufferedReader in = null;
14                 PrintWriter out = null;
15                   try {
16                     in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
17                     out = new PrintWriter(this.socket.getOutputStream(), true);
18                     String body = null;
19                       while(true){
20                         body = in.readLine();
21                           if(body == null) break;
22                             System.out.println("Server :" + body);
23                             out.println("服務器端回送響的應數據.");
24                     }
25                     } catch (Exception e) {
26                       e.printStackTrace();
27 
28                     }

 

  

  三:偽異步實現:

      原理:傳統的是直接new Thread()來進行運行任務,現在我們直接通過自定義線程池來實現偽異步。

       

1           //之前服務端運行:   
2 
3           //新建一個線程執行客戶端的任務
4           new Thread(new ServerHandler(socket)).start();

 

     

1           // 現在偽異步:
2 
3           HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 1000);
4             while(true){
5               socket = server.accept();
6               executorPool.execute(new ServerHandler(socket));
7             }

 

      自定義線程池:HandlerExecutorPool 

         

 1          public class HandlerExecutorPool {
 2 
 3             private ExecutorService executor;
 4             public HandlerExecutorPool(int maxPoolSize, int queueSize){
 5               this.executor = new ThreadPoolExecutor(
 6               Runtime.getRuntime().availableProcessors(),
 7               maxPoolSize, 
 8               120L, 
 9               TimeUnit.SECONDS,
10               new ArrayBlockingQueue<Runnable>(queueSize));
11               }
12 
13             public void execute(Runnable task){
14               this.executor.execute(task);
15             }
16 
17           }

 

 

  四:NIO(非阻塞編程)

        傳統IO和NIO的差異:IO是同步阻塞   NIO是同步非阻塞。 在jdk1.7以后,NIO升級(NIO2.0)AIO,實現了異步非阻塞

        傳統的IO(BIO)阻塞:在網絡應用程序獲取網絡數據時,如果網絡傳輸數據很慢,那么程序就一直等着,直到傳輸完畢為止。

        NIO:無需等待,直接獲取數據,在數據沒有傳輸完畢時,不獲取數據,數據暫時放在緩沖區,等傳輸完畢以后,緩沖區發出通知,客戶端獲取數據,實現不等待。

        

       基本概念:

          Buffer(緩沖區)   channel(管道、通道) Selector(選擇器,多路復用器)

          Buffer注意事項:每次在put(),for循環 之后都要進行flip()復位。要復位下標 

          Buffer常用方法:

                flip()復位:因為buffer和游標類似,每次新增數據之后,它的下標都會自增,如果用for循環遍歷時,他只會遍歷沒有填充的下標的值,所以要用filp()方法復

                      位。

                  wrap(數組):wrap方法會包裹一個數組: 一般這種用法不會先初始化緩存對象的長度,因為沒有意義,最后還會被wrap所包裹的數組覆蓋掉

                duplicate(): buffer復制的方法 。一個buffer數據復制給另外一個buffer數組

                position(index):設置buffer可讀的下標的位置

                remaining() :返回buffer可讀的長度

                get(數組):把buffer數據復制給數組

        

         Channel管道:雙向

                兩大類: 1:網絡讀寫類(SelectableChannel)   2:文件操作類(FileChannel)

                    我們要使用的SocketChannel和ServerSocketChannel就在SelectableChannel類里面

 

         Selector:選擇器(多路復用器)

                原理:Selector不斷的注冊輪詢注冊在其上的通道(SocketChannel),如果某一個通道發生了讀寫操作,這個通道就處於就緒狀態,會被Selector輪詢出

                     來。然后通過SelectionKey就可以獲取到就緒的Channel集合,從而進行后續操作。

                四大狀態:連接狀態   阻塞狀態   可讀狀態  可寫狀態

 

            

下面來看一下程序中是怎么通過這些類庫實現Socket功能。

 

首先介紹一下幾個輔助類

輔助類SerializableUtil,這個類用來把java對象序列化成字節數組,或者把字節數組反序列化成java對象。

 

[java]  view plain  copy
 
 print ?
  1. package com.googlecode.garbagecan.test.socket;  
  2.   
  3. import java.io.ByteArrayInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8.   
  9. public class SerializableUtil {  
  10.       
  11.     public static byte[] toBytes(Object object) {  
  12.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  13.         ObjectOutputStream oos = null;  
  14.         try {  
  15.             oos = new ObjectOutputStream(baos);  
  16.             oos.writeObject(object);  
  17.             byte[] bytes = baos.toByteArray();  
  18.             return bytes;  
  19.         } catch(IOException ex) {  
  20.             throw new RuntimeException(ex.getMessage(), ex);  
  21.         } finally {  
  22.             try {  
  23.                 oos.close();  
  24.             } catch (Exception e) {}  
  25.         }  
  26.     }  
  27.       
  28.     public static Object toObject(byte[] bytes) {  
  29.         ByteArrayInputStream bais = new ByteArrayInputStream(bytes);  
  30.         ObjectInputStream ois = null;  
  31.         try {  
  32.             ois = new ObjectInputStream(bais);  
  33.             Object object = ois.readObject();  
  34.             return object;  
  35.         } catch(IOException ex) {  
  36.             throw new RuntimeException(ex.getMessage(), ex);  
  37.         } catch(ClassNotFoundException ex) {  
  38.             throw new RuntimeException(ex.getMessage(), ex);  
  39.         } finally {  
  40.             try {  
  41.                 ois.close();  
  42.             } catch (Exception e) {}  
  43.         }  
  44.     }  
  45. }  

輔助類MyRequestObject和MyResponseObject,這兩個類是普通的java對象,實現了Serializable接口。MyRequestObject類是Client發出的請求,MyResponseObject是Server端作出的響應。

 

 

[java]  view plain  copy
 
 print ?
  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class MyRequestObject implements Serializable {  
  6.   
  7.     private static final long serialVersionUID = 1L;  
  8.   
  9.     private String name;  
  10.       
  11.     private String value;  
  12.   
  13.     private byte[] bytes;  
  14.       
  15.     public MyRequestObject(String name, String value) {  
  16.         this.name = name;  
  17.         this.value = value;  
  18.         this.bytes = new byte[1024];  
  19.     }  
  20.       
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.   
  25.     public void setName(String name) {  
  26.         this.name = name;  
  27.     }  
  28.   
  29.     public String getValue() {  
  30.         return value;  
  31.     }  
  32.   
  33.     public void setValue(String value) {  
  34.         this.value = value;  
  35.     }  
  36.       
  37.     @Override  
  38.     public String toString() {  
  39.         StringBuffer sb = new StringBuffer();  
  40.         sb.append("Request [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
  41.         return sb.toString();  
  42.     }  
  43. }  
  44.   
  45. package com.googlecode.garbagecan.test.socket.nio;  
  46.   
  47. import java.io.Serializable;  
  48.   
  49. public class MyResponseObject implements Serializable {  
  50.   
  51.     private static final long serialVersionUID = 1L;  
  52.   
  53.     private String name;  
  54.       
  55.     private String value;  
  56.   
  57.     private byte[] bytes;  
  58.       
  59.     public MyResponseObject(String name, String value) {  
  60.         this.name = name;  
  61.         this.value = value;  
  62.         this.bytes = new byte[1024];  
  63.     }  
  64.       
  65.     public String getName() {  
  66.         return name;  
  67.     }  
  68.   
  69.     public void setName(String name) {  
  70.         this.name = name;  
  71.     }  
  72.   
  73.     public String getValue() {  
  74.         return value;  
  75.     }  
  76.   
  77.     public void setValue(String value) {  
  78.         this.value = value;  
  79.     }  
  80.       
  81.     @Override  
  82.     public String toString() {  
  83.         StringBuffer sb = new StringBuffer();  
  84.         sb.append("Response [name: " + name  + ", value: " + value + ", bytes: " + bytes.length+ "]");  
  85.         return sb.toString();  
  86.     }  
  87. }  


下面主要看一下Server端的代碼,其中有一些英文注釋對理解代碼很有幫助,注釋主要是來源jdk的文檔和例子,這里就沒有再翻譯

 

 

[java]  view plain  copy
 
 print ?
  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.net.InetSocketAddress;  
  6. import java.nio.ByteBuffer;  
  7. import java.nio.channels.ClosedChannelException;  
  8. import java.nio.channels.SelectionKey;  
  9. import java.nio.channels.Selector;  
  10. import java.nio.channels.ServerSocketChannel;  
  11. import java.nio.channels.SocketChannel;  
  12. import java.util.Iterator;  
  13. import java.util.logging.Level;  
  14. import java.util.logging.Logger;  
  15.   
  16. import com.googlecode.garbagecan.test.socket.SerializableUtil;  
  17.   
  18. public class MyServer3 {  
  19.   
  20.     private final static Logger logger = Logger.getLogger(MyServer3.class.getName());  
  21.       
  22.     public static void main(String[] args) {  
  23.         Selector selector = null;  
  24.         ServerSocketChannel serverSocketChannel = null;  
  25.           
  26.         try {  
  27.             // Selector for incoming time requests  
  28.             selector = Selector.open();  
  29.   
  30.             // Create a new server socket and set to non blocking mode  
  31.             serverSocketChannel = ServerSocketChannel.open();  
  32.             serverSocketChannel.configureBlocking(false);  
  33.               
  34.             // Bind the server socket to the local host and port  
  35.             serverSocketChannel.socket().setReuseAddress(true);  
  36.             serverSocketChannel.socket().bind(new InetSocketAddress(10000));  
  37.               
  38.             // Register accepts on the server socket with the selector. This  
  39.             // step tells the selector that the socket wants to be put on the  
  40.             // ready list when accept operations occur, so allowing multiplexed  
  41.             // non-blocking I/O to take place.  
  42.             serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);  
  43.       
  44.             // Here's where everything happens. The select method will  
  45.             // return when any operations registered above have occurred, the  
  46.             // thread has been interrupted, etc.  
  47.             while (selector.select() > 0) {  
  48.                 // Someone is ready for I/O, get the ready keys  
  49.                 Iterator<SelectionKey> it = selector.selectedKeys().iterator();  
  50.       
  51.                 // Walk through the ready keys collection and process date requests.  
  52.                 while (it.hasNext()) {  
  53.                     SelectionKey readyKey = it.next();  
  54.                     it.remove();  
  55.                       
  56.                     // The key indexes into the selector so you  
  57.                     // can retrieve the socket that's ready for I/O  
  58.                     execute((ServerSocketChannel) readyKey.channel());  
  59.                 }  
  60.             }  
  61.         } catch (ClosedChannelException ex) {  
  62.             logger.log(Level.SEVERE, null, ex);  
  63.         } catch (IOException ex) {  
  64.             logger.log(Level.SEVERE, null, ex);  
  65.         } finally {  
  66.             try {  
  67.                 selector.close();  
  68.             } catch(Exception ex) {}  
  69.             try {  
  70.                 serverSocketChannel.close();  
  71.             } catch(Exception ex) {}  
  72.         }  
  73.     }  
  74.   
  75.     private static void execute(ServerSocketChannel serverSocketChannel) throws IOException {  
  76.         SocketChannel socketChannel = null;  
  77.         try {  
  78.             socketChannel = serverSocketChannel.accept();  
  79.             MyRequestObject myRequestObject = receiveData(socketChannel);  
  80.             logger.log(Level.INFO, myRequestObject.toString());  
  81.               
  82.             MyResponseObject myResponseObject = new MyResponseObject(  
  83.                     "response for " + myRequestObject.getName(),   
  84.                     "response for " + myRequestObject.getValue());  
  85.             sendData(socketChannel, myResponseObject);  
  86.             logger.log(Level.INFO, myResponseObject.toString());  
  87.         } finally {  
  88.             try {  
  89.                 socketChannel.close();  
  90.             } catch(Exception ex) {}  
  91.         }  
  92.     }  
  93.       
  94.     private static MyRequestObject receiveData(SocketChannel socketChannel) throws IOException {  
  95.         MyRequestObject myRequestObject = null;  
  96.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  97.         ByteBuffer buffer = ByteBuffer.allocate(1024);  
  98.           
  99.         try {  
  100.             byte[] bytes;  
  101.             int size = 0;  
  102.             while ((size = socketChannel.read(buffer)) >= 0) {  
  103.                 buffer.flip();  
  104.                 bytes = new byte[size];  
  105.                 buffer.get(bytes);  
  106.                 baos.write(bytes);  
  107.                 buffer.clear();  
  108.             }  
  109.             bytes = baos.toByteArray();  
  110.             Object obj = SerializableUtil.toObject(bytes);  
  111.             myRequestObject = (MyRequestObject)obj;  
  112.         } finally {  
  113.             try {  
  114.                 baos.close();  
  115.             } catch(Exception ex) {}  
  116.         }  
  117.         return myRequestObject;  
  118.     }  
  119.   
  120.     private static void sendData(SocketChannel socketChannel, MyResponseObject myResponseObject) throws IOException {  
  121.         byte[] bytes = SerializableUtil.toBytes(myResponseObject);  
  122.         ByteBuffer buffer = ByteBuffer.wrap(bytes);  
  123.         socketChannel.write(buffer);  
  124.     }  
  125. }  

下面是Client的代碼,代碼比較簡單就是啟動了100個線程來訪問Server

 

 

[java]  view plain  copy
 
 print ?
  1. package com.googlecode.garbagecan.test.socket.nio;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.IOException;  
  5. import java.net.InetSocketAddress;  
  6. import java.net.SocketAddress;  
  7. import java.nio.ByteBuffer;  
  8. import java.nio.channels.SocketChannel;  
  9. import java.util.logging.Level;  
  10. import java.util.logging.Logger;  
  11.   
  12. import com.googlecode.garbagecan.test.socket.SerializableUtil;  
  13.   
  14. public class MyClient3 {  
  15.   
  16.     private final static Logger logger = Logger.getLogger(MyClient3.class.getName());  
  17.       
  18.     public static void main(String[] args) throws Exception {  
  19.         for (int i = 0; i < 100; i++) {  
  20.             final int idx = i;  
  21.             new Thread(new MyRunnable(idx)).start();  
  22.         }  
  23.     }  
  24.       
  25.     private static final class MyRunnable implements Runnable {  
  26.           
  27.         private final int idx;  
  28.   
  29.         private MyRunnable(int idx) {  
  30.             this.idx = idx;  
  31.         }  
  32.   
  33.         public void run() {  
  34.             SocketChannel socketChannel = null;  
  35.             try {  
  36.                 socketChannel = SocketChannel.open();  
  37.                 SocketAddress socketAddress = new InetSocketAddress("localhost"10000);  
  38.                 socketChannel.connect(socketAddress);  
  39.   
  40.                 MyRequestObject myRequestObject = new MyRequestObject("request_" + idx, "request_" + idx);  
  41.                 logger.log(Level.INFO, myRequestObject.toString());  
  42.                 sendData(socketChannel, myRequestObject);  
  43.                   
  44.                 MyResponseObject myResponseObject = receiveData(socketChannel);  
  45.                 logger.log(Level.INFO, myResponseObject.toString());  
  46.             } catch (Exception ex) {  
  47.                 logger.log(Level.SEVERE, null, ex);  
  48.             } finally {  
  49.                 try {  
  50.                     socketChannel.close();  
  51.                 } catch(Exception ex) {}  
  52.             }  
  53.         }  
  54.   
  55.         private void sendData(SocketChannel socketChannel, MyRequestObject myRequestObject) throws IOException {  
  56.             byte[] bytes = SerializableUtil.toBytes(myRequestObject);  
  57.             ByteBuffer buffer = ByteBuffer.wrap(bytes);  
  58.             socketChannel.write(buffer);  
  59.             socketChannel.socket().shutdownOutput();  
  60.         }  
  61.   
  62.         private MyResponseObject receiveData(SocketChannel socketChannel) throws IOException {  
  63.             MyResponseObject myResponseObject = null;  
  64.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  65.               
  66.             try {  
  67.                 ByteBuffer buffer = ByteBuffer.allocateDirect(1024);  
  68.                 byte[] bytes;  
  69.                 int count = 0;  
  70.                 while ((count = socketChannel.read(buffer)) >= 0) {  
  71.                     buffer.flip();  
  72.                     bytes = new byte[count];  
  73.                     buffer.get(bytes);  
  74.                     baos.write(bytes);  
  75.                     buffer.clear();  
  76.                 }  
  77.                 bytes = baos.toByteArray();  
  78.                 Object obj = SerializableUtil.toObject(bytes);  
  79.                 myResponseObject = (MyResponseObject) obj;  
  80.                 socketChannel.socket().shutdownInput();  
  81.             } finally {  
  82.                 try {  
  83.                     baos.close();  
  84.                 } catch(Exception ex) {}  
  85.             }  
  86.             return myResponseObject;  
  87.         }  
  88.     }  
  89. }  
 

 

最后測試上面的代碼,首先運行Server類,然后運行Client類,就可以分別在Server端和Client端控制台看到發送或接收到的MyRequestObject或MyResponseObject對象了。   

 

代碼實現: 

         注:轉自http://blog.csdn.net/kongxx/article/details/7288896

    

 

 

  五:NIO2.0(AIO) 異步非阻塞

 

      AIO編程:在NIO基礎上引入異步的通到的概念,實現了異步文件和異步套字節,jdk1.7以后升級。

    

        基本概念

          1 AsynchronousChannel:支持異步通道,包括服務端AsynchronousServerSocketChannel和客戶端AsynchronousSocketChannel等實現。
          2 CompletionHandler:用戶處理器。定義了一個用戶處理就緒事件的接口,由用戶自己實現,異步io的數據就緒后回調該處理器消費或處理數據。
          3 AsynchronousChannelGroup:一個用於資源共享的異步通道集合。處理IO事件和分配給CompletionHandler。(具體這塊還沒細看代碼,后續再分析這塊)

 

    

      所謂AIO,就是異步非阻塞IO,是NIO的升級版本,也就是NIO2.0版本,但是與NIO不同,當進行讀寫操作時,只須直接調用API的read或write方法即可。這兩種方法均為異步

        的,對於讀操作而言,當有流可讀取時,操作系統會將可讀的流傳入read方法的緩沖區,並通知應用程序;對於寫操作而言,當操作系統將write方法傳遞的流寫入完畢時,操作

        系統主動通知應用程序。 即可以理解為,read/write方法都是異步的,完成后會主動調用回調函數。

 

      具體代碼實現:

           

 1            // Server類: 
 2 
 3 
 4 
 5 /**
 6 * 
 7 *類描述:AIO 服務端
 8 *@author: 豪
 9 *@date: 日期:2017-5-24 時間:上午10:48:12
10 *@version 1.0
11 */
12 public class Server {
13 //線程池
14 private ExecutorService executorService;
15 //線程組
16 private AsynchronousChannelGroup threadGroup;
17 //服務器通道
18 public AsynchronousServerSocketChannel assc;
19 
20 public Server(int port){
21 try {
22 //創建一個緩存池
23 executorService = Executors.newCachedThreadPool();
24 //創建線程組
25 threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
26 //創建服務器通道
27 assc = AsynchronousServerSocketChannel.open(threadGroup);
28 //進行綁定
29 assc.bind(new InetSocketAddress(port));
30 
31 System.out.println("server start , port : " + port);
32 //進行阻塞
33 assc.accept(this, new ServerCompletionHandler());
34 //一直阻塞 不讓服務器停止
35 Thread.sleep(Integer.MAX_VALUE);
36 
37 } catch (Exception e) {
38 e.printStackTrace();
39 }
40 }
41 
42 public static void main(String[] args) {
43 Server server = new Server(8765);
44 }
45 
46 }

 

 

 1 //ServerCompletionHandler類
 2    
 3 
 4 /**
 5 * 
 6 *類描述:服務端處理類 所有的處理都在此類進行
 7 *@author: 豪
 8 *@date: 日期:2017-5-24 時間:上午10:47:45
 9 *@version 1.0
10 */
11 public class ServerCompletionHandler implements CompletionHandler<AsynchronousSocketChannel, Server> {
12 
13 @Override
14 public void completed(AsynchronousSocketChannel asc, Server attachment) {
15 //當有下一個客戶端接入的時候 直接調用Server的accept方法,這樣反復執行下去,保證多個客戶端都可以阻塞
16 attachment.assc.accept(attachment, this);
17 read(asc);
18 }
19 
20 private void read(final AsynchronousSocketChannel asc) {
21 //讀取數據
22 ByteBuffer buf = ByteBuffer.allocate(1024);
23 asc.read(buf, buf, new CompletionHandler<Integer, ByteBuffer>() {
24 @Override
25 public void completed(Integer resultSize, ByteBuffer attachment) {
26 //進行讀取之后,重置標識位
27 attachment.flip();
28 //獲得讀取的字節數
29 System.out.println("Server -> " + "收到客戶端的數據長度為:" + resultSize);
30 //獲取讀取的數據
31 String resultData = new String(attachment.array()).trim();
32 System.out.println("Server -> " + "收到客戶端的數據信息為:" + resultData);
33 String response = "服務器響應, 收到了客戶端發來的數據: " + resultData;
34 write(asc, response);
35 }
36 @Override
37 public void failed(Throwable exc, ByteBuffer attachment) {
38 exc.printStackTrace();
39 }
40 });
41 }
42 
43 private void write(AsynchronousSocketChannel asc, String response) {
44 try {
45 ByteBuffer buf = ByteBuffer.allocate(1024);
46 buf.put(response.getBytes());
47 buf.flip();
48 asc.write(buf).get();
49 } catch (InterruptedException e) {
50 e.printStackTrace();
51 } catch (ExecutionException e) {
52 e.printStackTrace();
53 }
54 }
55 
56 @Override
57 public void failed(Throwable exc, Server attachment) {
58 exc.printStackTrace();
59 }
60 
61 }

 

 

 1 //Clinet類:
 2 
 3 /**
 4 * 
 5 *類描述:AIO客戶端
 6 *@author: 豪
 7 *@date: 日期:2017-5-24 時間:上午10:47:23
 8 *@version 1.0
 9 */
10 public class Client implements Runnable{
11 
12 private AsynchronousSocketChannel asc ;
13 
14 public Client() throws Exception {
15 asc = AsynchronousSocketChannel.open();
16 }
17 
18 public void connect(){
19 asc.connect(new InetSocketAddress("127.0.0.1", 8765));
20 }
21 
22 public void write(String request){
23 try {
24 asc.write(ByteBuffer.wrap(request.getBytes())).get();
25 read();
26 } catch (Exception e) {
27 e.printStackTrace();
28 }
29 }
30 
31 private void read() {
32 ByteBuffer buf = ByteBuffer.allocate(1024);
33 try {
34 asc.read(buf).get();
35 buf.flip();
36 byte[] respByte = new byte[buf.remaining()];
37 buf.get(respByte);
38 System.out.println(new String(respByte,"utf-8").trim());
39 } catch (InterruptedException e) {
40 e.printStackTrace();
41 } catch (ExecutionException e) {
42 e.printStackTrace();
43 } catch (UnsupportedEncodingException e) {
44 e.printStackTrace();
45 }
46 }
47 
48 @Override
49 public void run() {
50 while(true){
51 
52 }
53 }
54 
55 public static void main(String[] args) throws Exception {
56 Client c1 = new Client();
57 c1.connect();
58 
59 Client c2 = new Client();
60 c2.connect();
61 
62 Client c3 = new Client();
63 c3.connect();
64 
65 new Thread(c1, "c1").start();
66 new Thread(c2, "c2").start();
67 new Thread(c3, "c3").start();
68 
69 Thread.sleep(1000);
70 
71 c1.write("c1 aaa");
72 c2.write("c2 bbbb");
73 c3.write("c3 ccccc");
74 }
75 
76 }

   

            


免責聲明!

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



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