站長資訊網
        最全最豐富的資訊網站

        Java NIO非阻塞服務器示例

        以前一直用的是“ervery thread per
        connection”的服務器端模式,今天試了下NIO非阻塞模式的服務器。

          以前一直用的是“ervery thread per connection”的服務器端模式,今天試了下NIO非阻塞模式的服務器。
          不過java不能實現I/O完成端口模型,這點很遺憾。

                           
          1. package com.vista.Server;
          2. import java.io.IOException;
          3. import java.net.InetSocketAddress;
          4. import java.net.ServerSocket;
          5. import java.nio.ByteBuffer;
          6. import java.nio.channels.SelectionKey;
          7. import java.nio.channels.Selector;
          8. import java.nio.channels.ServerSocketChannel;
          9. import java.nio.channels.SocketChannel;
          10. import java.util.Iterator;
          11. import java.util.LinkedList;
          12. import java.util.Set;
          13. public class SelectorServer
          14. {
          15. private static int DEFAULT_SERVERPORT = 6018;//默認端口
          16. private static int DEFAULT_BUFFERSIZE = 1024;//默認緩沖區大小為1024字節
          17. private ServerSocketChannel channel;
          18. private LinkedList<SocketChannel> clients;
          19. private Selector readSelector;
          20. private ByteBuffer buffer;//字節緩沖區
          21. private int port;
          22. public SelectorServer(int port) throws IOException
          23. {
          24. this.port = port;
          25. this.clients = new LinkedList<SocketChannel>();
          26. this.channel = null;
          27. this.readSelector = Selector.open();//打開選擇器
          28. this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
          29. }
          30. // 服務器程序在服務循環中調用sericeClients()方法為已接受的客戶服務
          31. public void serviceClients()throws IOException
          32. {
          33. Set keys;
          34. Iterator it;
          35. SelectionKey key;
          36. SocketChannel client;
          37. // 在readSelector上調用select()方法,參數1代表如果調用select的時候 那么阻塞最多1秒鐘等待可用的客戶端連接
          38. if(readSelector.select(1) > 0)
          39. {
          40. keys = readSelector.selectedKeys(); // 取得代表端通道的鍵集合
          41. it = keys.iterator();
          42. // 遍歷,為每一個客戶服務
          43. while(it.hasNext())
          44. {
          45. key = (SelectionKey)it.next();
          46. if(key.isReadable())
          47. { // 如果通道可讀,那么讀此通道到buffer中
          48. int bytes;
          49. client = (SocketChannel)key.channel();// 取得鍵對應的通道
          50. buffer.clear(); // 清空緩沖區中的內容,設置好position,limit,準備接受數據
          51. bytes = client.read(buffer); // 從通道中讀數據到緩沖中,返回讀取得字節數
          52. if(bytes >= 0)
          53. {
          54. buffer.flip(); // 準備將緩沖中的數據寫回到通道中
          55. client.write(buffer); // 數據寫回到通道中
          56. }
          57. else if(bytes < 0)
          58. { // 如果返回小于零的值代表讀到了流的末尾
          59. clients.remove(client);
          60. // 通道關閉時,選擇鍵也被取消
          61. client.close();
          62. }
          63. }
          64. }
          65. }
          66. }
          67. public void registerClient(SocketChannel client) throws IOException
          68. {// 配置和注冊代表客戶連接的通道對象
          69. client.configureBlocking(false); // 設置此通道使用非阻塞模式
          70. client.register(readSelector, SelectionKey.OP_READ); // 將這個通道注冊到選擇器上
          71. clients.add(client); //保存這個通道對象
          72. }
          73. public void listen() throws IOException
          74. { //服務器開始監聽端口,提供服務
          75. ServerSocket socket;
          76. SocketChannel client;
          77. channel = ServerSocketChannel.open(); // 打開通道
          78. socket = channel.socket(); //得到與通到相關的socket對象
          79. socket.bind(new InetSocketAddress(port), 10); //將scoket榜定在制定的端口上
          80. //配置通到使用非阻塞模式,在非阻塞模式下,可以編寫多道程序同時避免使用復雜的多線程
          81. channel.configureBlocking(false);
          82. try
          83. {
          84. while(true)
          85. {// 與通常的程序不同,這里使用channel.accpet()接受客戶端連接請求,而不是在socket對象上調用accept(),這里在調用accept()方法時如果通道配置為非阻塞模式,那么accept()方法立即返回null,并不阻塞
          86. client = channel.accept();
          87. if(client != null)
          88. {
          89. registerClient(client); // 注冊客戶信息
          90. }
          91. serviceClients(); // 為以連接的客戶服務
          92. }
          93. }
          94. finally
          95. {
          96. socket.close(); // 關閉socket,關閉socket會同時關閉與此socket關聯的通道
          97. }
          98. }
          99. public static void main(String[] args) throws IOException
          100. {
          101. System.out.println(“服務器啟動”);
          102. SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);
          103. server.listen(); //服務器開始監聽端口,提供服務
          104. }
          105. }
           

          修改版本:

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   
          1. package com.vista.Server;
          2. import java.io.BufferedWriter;
          3. import java.io.FileInputStream;
          4. import java.io.IOException;
          5. import java.io.OutputStreamWriter;
          6. import java.io.PrintWriter;
          7. import java.net.InetSocketAddress;
          8. import java.net.ServerSocket;
          9. import java.nio.ByteBuffer;
          10. import java.nio.CharBuffer;
          11. import java.nio.channels.FileChannel;
          12. import java.nio.channels.SelectionKey;
          13. import java.nio.channels.Selector;
          14. import java.nio.channels.ServerSocketChannel;
          15. import java.nio.channels.SocketChannel;
          16. import java.nio.charset.Charset;
          17. import java.nio.charset.CharsetDecoder;
          18. import java.util.Iterator;
          19. import java.util.LinkedList;
          20. import java.util.Set;
          21. public class SelectorServer
          22. {
          23. private static int DEFAULT_SERVERPORT = 6018;//默認端口
          24. private static int DEFAULT_BUFFERSIZE = 1024;//默認緩沖區大小為1024字節
          25. private static String DEFAULT_CHARSET = “GB2312”;//默認碼集
          26. private static String DEFAULT_FILENAME = “bigfile.dat”;
          27. private ServerSocketChannel channel;
          28. private LinkedList<SocketChannel> clients;
          29. private Selector selector;//選擇器
          30. private ByteBuffer buffer;//字節緩沖區
          31. private int port;
          32. private Charset charset;//字符集
          33. private CharsetDecoder decoder;//解碼器
          34. public SelectorServer(int port) throws IOException
          35. {
          36. this.port = port;
          37. this.clients = new LinkedList<SocketChannel>();
          38. this.channel = null;
          39. this.selector = Selector.open();//打開選擇器
          40. this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
          41. this.charset = Charset.forName(DEFAULT_CHARSET);
          42. this.decoder = this.charset.newDecoder();
          43. }
          44. private class HandleClient
          45. {
          46. private String strGreeting = “welcome to VistaQQ”;
          47. public HandleClient() throws IOException
          48. {
          49. }
          50. public String readBlock()
          51. {//讀塊數據
          52. return this.strGreeting;
          53. }
          54. public void close()
          55. {
          56. }
          57. }
          58. protected void handleKey(SelectionKey key) throws IOException
          59. {//處理事件
          60. if (key.isAcceptable())
          61. { // 接收請求
          62. ServerSocketChannel server = (ServerSocketChannel) key.channel();//取出對應的服務器通道
          63. SocketChannel channel = server.accept();
          64. channel.configureBlocking(false);
          65. channel.register(selector, SelectionKey.OP_READ);//客戶socket通道注冊讀操作
          66. }
          67. else if (key.isReadable())
          68. { // 讀信息
          69. SocketChannel channel = (SocketChannel) key.channel();
          70. int count = channel.read(this.buffer);
          71. if (count > 0)
          72. {
          73. this.buffer.flip();
          74. CharBuffer charBuffer = decoder.decode(this.buffer);
          75. System.out.println(“Client >>” + charBuffer.toString());
          76. SelectionKey wKey = channel.register(selector,
          77. SelectionKey.OP_WRITE);//為客戶sockt通道注冊寫操作
          78. wKey.attach(new HandleClient());
          79. }
          80. else
          81. {//客戶已經斷開
          82. channel.close();
          83. }
          84. this.buffer.clear();//清空緩沖區
          85. }
          86. else if (key.isWritable())
          87. { // 寫事件
          88. SocketChannel channel = (SocketChannel) key.channel();
          89. HandleClient handle = (HandleClient) key.attachment();//取出處理者
          90. ByteBuffer block = ByteBuffer.wrap(handle.readBlock().getBytes());
          91. channel.write(block);
          92. // channel.socket().getInputStream().(block);
          93. // PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
          94. // channel.socket().getOutputStream())), true);
          95. // out.write(block.toString());
          96. }
          97. }
          98. public void listen() throws IOException
          99. { //服務器開始監聽端口,提供服務
          100. ServerSocket socket;
          101. channel = ServerSocketChannel.open(); // 打開通道
          102. socket = channel.socket(); //得到與通到相關的socket對象
          103. socket.bind(new InetSocketAddress(port)); //將scoket榜定在制定的端口上
          104. //配置通到使用非阻塞模式,在非阻塞模式下,可以編寫多道程序同時避免使用復雜的多線程
          105. channel.configureBlocking(false);
          106. channel.register(selector, SelectionKey.OP_ACCEPT);
          107. try
          108. {
          109. while(true)
          110. {// 與通常的程序不同,這里使用channel.accpet()接受客戶端連接請求,而不是在socket對象上調用accept(),這里在調用accept()方法時如果通道配置為非阻塞模式,那么accept()方法立即返回null,并不阻塞
          111. this.selector.select();
          112. Iterator iter = this.selector.selectedKeys().iterator();
          113. while(iter.hasNext())
          114. {
          115. SelectionKey key = (SelectionKey)iter.next();
          116. iter.remove();
          117. this.handleKey(key);
          118. }
          119. }
          120. }
          121. catch(IOException ex)
          122. {
          123. ex.printStackTrace();
          124. }
          125. }
          126. public static void main(String[] args) throws IOException
          127. {
          128. System.out.println(“服務器啟動”);
          129. SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);
          130. server.listen(); //服務器開始監聽端口,提供服務
          131. }
          132. }
           

          贊(0)
          分享到: 更多 (0)
          網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
          主站蜘蛛池模板: 91精品欧美综合在线观看| 国内精品手机在线观看视频| 99在线精品一区二区三区| 久久亚洲国产成人精品无码区| 99re8这里有精品热视频免费| 日韩熟女精品一区二区三区 | 欧美精品/日韩精品/国产精品 | 好湿好大硬得深一点动态图91精品福利一区二区| 亚洲精品国偷自产在线| 久久99精品久久久久久水蜜桃 | 国产精品高清2021在线 | 国精品午夜福利视频不卡| 亚洲精品天堂成人片?V在线播放| 精品久久久久久国产免费了| 成人午夜精品亚洲日韩| 欧美视频精品一区二区三区| 久久国产成人精品麻豆| 精品久久久久久国产91| 国产精品久久一区二区三区| 国产精品对白交换视频| 精品三级AV无码一区| 久热这里只有精品12| 无码精品国产一区二区三区免费| 亚洲精品国产日韩无码AV永久免费网| 欧美人与性动交α欧美精品| 精品无码一级毛片免费视频观看| 国产精品无打码在线播放| 国产女人18毛片水真多18精品 | 2020久久精品国产免费| 992tv精品视频tv在线观看| jiucao在线观看精品| 国产精品素人搭讪在线播放| 国产精品视频分类一区| 99精品久久精品| 国内精品伊人久久久久| 中文字幕成人精品久久不卡| 国产成人精品综合在线观看| 国产精品青草视频免费播放| 精品免费久久久久国产一区| 日韩人妻无码精品无码中文字幕| 亚洲午夜成人精品电影在线观看|