Java NIO編寫Socket服務器的一個例子

最近一直在忙著JAVA NIO的知識,花了一下午的時間,總算寫出了一個可以運行的程序,廢話少說,上代碼!

Java代碼:

  1. import?java.io.IOException; ?
  2. import?java.net.InetSocketAddress; ?
  3. import?java.net.ServerSocket; ?
  4. import?java.nio.ByteBuffer; ?
  5. import?java.nio.channels.SelectionKey; ?
  6. import?java.nio.channels.Selector; ?
  7. import?java.nio.channels.ServerSocketChannel; ?
  8. import?java.nio.channels.SocketChannel; ?
  9. import?java.util.Iterator; ?
  10. import?java.util.Set; ?
  11. ?
  12. public?class?NIOServer?{ ?
  13. ???? ?
  14. ????/*標識數字*/?
  15. ????private??int?flag?=?0; ?
  16. ????/*緩沖區大小*/?
  17. ????private??int?BLOCK?=?4096; ?
  18. ????/*接受數據緩沖區*/?
  19. ????private??ByteBuffer?sendbuffer?=?ByteBuffer.allocate(BLOCK); ?
  20. ????/*發送數據緩沖區*/?
  21. ????private??ByteBuffer?receivebuffer?=?ByteBuffer.allocate(BLOCK); ?
  22. ????private??Selector?selector; ?
  23. ?
  24. ????public?NIOServer(int?port)?throws?IOException?{ ?
  25. ????????//?打開服務器套接字通道 ?
  26. ????????ServerSocketChannel?serverSocketChannel?=?ServerSocketChannel.open(); ?
  27. ????????//?服務器配置為非阻塞 ?
  28. ????????serverSocketChannel.configureBlocking(false); ?
  29. ????????//?檢索與此通道關聯的服務器套接字 ?
  30. ????????ServerSocket?serverSocket?=?serverSocketChannel.socket(); ?
  31. ????????//?進行服務的綁定 ?
  32. ????????serverSocket.bind(new?InetSocketAddress(port)); ?
  33. ????????//?通過open()方法找到Selector ?
  34. ????????selector?=?Selector.open(); ?
  35. ????????//?注冊到selector,等待連接 ?
  36. ????????serverSocketChannel.register(selector,?SelectionKey.OP_ACCEPT); ?
  37. ????????System.out.println("Server?Start----8888:"); ?
  38. ????} ?
  39. ?
  40. ?
  41. ????//?監聽 ?
  42. ????private?void?listen()?throws?IOException?{ ?
  43. ????????while?(true)?{ ?
  44. ????????????//?選擇一組鍵,并且相應的通道已經打開 ?
  45. ????????????selector.select(); ?
  46. ????????????//?返回此選擇器的已選擇鍵集。 ?
  47. ????????????Set<SelectionKey>?selectionKeys?=?selector.selectedKeys(); ?
  48. ????????????Iterator<SelectionKey>?iterator?=?selectionKeys.iterator(); ?
  49. ????????????while?(iterator.hasNext())?{???????? ?
  50. ????????????????SelectionKey?selectionKey?=?iterator.next(); ?
  51. ????????????????iterator.remove(); ?
  52. ????????????????handleKey(selectionKey); ?
  53. ????????????} ?
  54. ????????} ?
  55. ????} ?
  56. ?
  57. ????//?處理請求 ?
  58. ????private?void?handleKey(SelectionKey?selectionKey)?throws?IOException?{ ?
  59. ????????//?接受請求 ?
  60. ????????ServerSocketChannel?server?=?null; ?
  61. ????????SocketChannel?client?=?null; ?
  62. ????????String?receiveText; ?
  63. ????????String?sendText; ?
  64. ????????int?count=0; ?
  65. ????????//?測試此鍵的通道是否已準備好接受新的套接字連接。 ?
  66. ????????if?(selectionKey.isAcceptable())?{ ?
  67. ????????????//?返回為之創建此鍵的通道。 ?
  68. ????????????server?=?(ServerSocketChannel)?selectionKey.channel(); ?
  69. ????????????//?接受到此通道套接字的連接。 ?
  70. ????????????//?此方法返回的套接字通道(如果有)將處于阻塞模式。 ?
  71. ????????????client?=?server.accept(); ?
  72. ????????????//?配置為非阻塞 ?
  73. ????????????client.configureBlocking(false); ?
  74. ????????????//?注冊到selector,等待連接 ?
  75. ????????????client.register(selector,?SelectionKey.OP_READ); ?
  76. ????????}?else?if?(selectionKey.isReadable())?{ ?
  77. ????????????//?返回為之創建此鍵的通道。 ?
  78. ????????????client?=?(SocketChannel)?selectionKey.channel(); ?
  79. ????????????//將緩沖區清空以備下次讀取 ?
  80. ????????????receivebuffer.clear(); ?
  81. ????????????//讀取服務器發送來的數據到緩沖區中 ?
  82. ????????????count?=?client.read(receivebuffer);? ?
  83. ????????????if?(count?>?0)?{ ?
  84. ????????????????receiveText?=?new?String(?receivebuffer.array(),0,count); ?
  85. ????????????????System.out.println("服務器端接受客戶端數據--:"+receiveText); ?
  86. ????????????????client.register(selector,?SelectionKey.OP_WRITE); ?
  87. ????????????} ?
  88. ????????}?else?if?(selectionKey.isWritable())?{ ?
  89. ????????????//將緩沖區清空以備下次寫入 ?
  90. ????????????sendbuffer.clear(); ?
  91. ????????????//?返回為之創建此鍵的通道。 ?
  92. ????????????client?=?(SocketChannel)?selectionKey.channel(); ?
  93. ????????????sendText="message?from?server--"?+?flag++; ?
  94. ????????????//向緩沖區中輸入數據 ?
  95. ????????????sendbuffer.put(sendText.getBytes()); ?
  96. ?????????????//將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位 ?
  97. ????????????sendbuffer.flip(); ?
  98. ????????????//輸出到通道 ?
  99. ????????????client.write(sendbuffer); ?
  100. ????????????System.out.println("服務器端向客戶端發送數據--:"+sendText); ?
  101. ????????????client.register(selector,?SelectionKey.OP_READ); ?
  102. ????????} ?
  103. ????} ?
  104. ?
  105. ????/** ?
  106. ?????*?@param?args ?
  107. ?????*?@throws?IOException ?
  108. ?????*/?
  109. ????public?static?void?main(String[]?args)?throws?IOException?{ ?
  110. ????????//?TODO?Auto-generated?method?stub ?
  111. ????????int?port?=?8888; ?
  112. ????????NIOServer?server?=?new?NIOServer(port); ?
  113. ????????server.listen(); ?
  114. ????} ?
  115. }?

Java代碼:

  1. import?java.io.IOException; ?
  2. import?java.net.InetSocketAddress; ?
  3. import?java.nio.ByteBuffer; ?
  4. import?java.nio.channels.SelectionKey; ?
  5. import?java.nio.channels.Selector; ?
  6. import?java.nio.channels.SocketChannel; ?
  7. import?java.util.Iterator; ?
  8. import?java.util.Set; ?
  9. ?
  10. public?class?NIOClient?{ ?
  11. ?
  12. ????/*標識數字*/?
  13. ????private?static?int?flag?=?0; ?
  14. ????/*緩沖區大小*/?
  15. ????private?static?int?BLOCK?=?4096; ?
  16. ????/*接受數據緩沖區*/?
  17. ????private?static?ByteBuffer?sendbuffer?=?ByteBuffer.allocate(BLOCK); ?
  18. ????/*發送數據緩沖區*/?
  19. ????private?static?ByteBuffer?receivebuffer?=?ByteBuffer.allocate(BLOCK); ?
  20. ????/*服務器端地址*/?
  21. ????private?final?static?InetSocketAddress?SERVER_ADDRESS?=?new?InetSocketAddress( ?
  22. ????????????"localhost",?1111); ?
  23. ?
  24. ????public?static?void?main(String[]?args)?throws?IOException?{ ?
  25. ????????//?TODO?Auto-generated?method?stub ?
  26. ????????//?打開socket通道 ?
  27. ????????SocketChannel?socketChannel?=?SocketChannel.open(); ?
  28. ????????//?設置為非阻塞方式 ?
  29. ????????socketChannel.configureBlocking(false); ?
  30. ????????//?打開選擇器 ?
  31. ????????Selector?selector?=?Selector.open(); ?
  32. ????????//?注冊連接服務端socket動作 ?
  33. ????????socketChannel.register(selector,?SelectionKey.OP_CONNECT); ?
  34. ????????//?連接 ?
  35. ????????socketChannel.connect(SERVER_ADDRESS); ?
  36. ????????//?分配緩沖區大小內存 ?
  37. ???????? ?
  38. ????????Set<SelectionKey>?selectionKeys; ?
  39. ????????Iterator<SelectionKey>?iterator; ?
  40. ????????SelectionKey?selectionKey; ?
  41. ????????SocketChannel?client; ?
  42. ????????String?receiveText; ?
  43. ????????String?sendText; ?
  44. ????????int?count=0; ?
  45. ?
  46. ????????while?(true)?{ ?
  47. ????????????//選擇一組鍵,其相應的通道已為?I/O?操作準備就緒。 ?
  48. ????????????//此方法執行處于阻塞模式的選擇操作。 ?
  49. ????????????selector.select(); ?
  50. ????????????//返回此選擇器的已選擇鍵集。 ?
  51. ????????????selectionKeys?=?selector.selectedKeys(); ?
  52. ????????????//System.out.println(selectionKeys.size()); ?
  53. ????????????iterator?=?selectionKeys.iterator(); ?
  54. ????????????while?(iterator.hasNext())?{ ?
  55. ????????????????selectionKey?=?iterator.next(); ?
  56. ????????????????if?(selectionKey.isConnectable())?{ ?
  57. ????????????????????System.out.println("client?connect"); ?
  58. ????????????????????client?=?(SocketChannel)?selectionKey.channel(); ?
  59. ????????????????????//?判斷此通道上是否正在進行連接操作。 ?
  60. ????????????????????//?完成套接字通道的連接過程。 ?
  61. ????????????????????if?(client.isConnectionPending())?{ ?
  62. ????????????????????????client.finishConnect(); ?
  63. ????????????????????????System.out.println("完成連接!"); ?
  64. ????????????????????????sendbuffer.clear(); ?
  65. ????????????????????????sendbuffer.put("Hello,Server".getBytes()); ?
  66. ????????????????????????sendbuffer.flip(); ?
  67. ????????????????????????client.write(sendbuffer); ?
  68. ????????????????????} ?
  69. ????????????????????client.register(selector,?SelectionKey.OP_READ); ?
  70. ????????????????}?else?if?(selectionKey.isReadable())?{ ?
  71. ????????????????????client?=?(SocketChannel)?selectionKey.channel(); ?
  72. ????????????????????//將緩沖區清空以備下次讀取 ?
  73. ????????????????????receivebuffer.clear(); ?
  74. ????????????????????//讀取服務器發送來的數據到緩沖區中 ?
  75. ????????????????????count=client.read(receivebuffer); ?
  76. ????????????????????if(count>0){ ?
  77. ????????????????????????receiveText?=?new?String(?receivebuffer.array(),0,count); ?
  78. ????????????????????????System.out.println("客戶端接受服務器端數據--:"+receiveText); ?
  79. ????????????????????????client.register(selector,?SelectionKey.OP_WRITE); ?
  80. ????????????????????} ?
  81. ?
  82. ????????????????}?else?if?(selectionKey.isWritable())?{ ?
  83. ????????????????????sendbuffer.clear(); ?
  84. ????????????????????client?=?(SocketChannel)?selectionKey.channel(); ?
  85. ????????????????????sendText?=?"message?from?client--"?+?(flag++); ?
  86. ????????????????????sendbuffer.put(sendText.getBytes()); ?
  87. ?????????????????????//將緩沖區各標志復位,因為向里面put了數據標志被改變要想從中讀取數據發向服務器,就要復位 ?
  88. ????????????????????sendbuffer.flip(); ?
  89. ????????????????????client.write(sendbuffer); ?
  90. ????????????????????System.out.println("客戶端向服務器端發送數據--:"+sendText); ?
  91. ????????????????????client.register(selector,?SelectionKey.OP_READ); ?
  92. ????????????????} ?
  93. ????????????} ?
  94. ????????????selectionKeys.clear(); ?
  95. ????????} ?
  96. ????} ?
  97. }?

個人感覺,JAVA NIO的操作時麻煩了不少,但是無疑這樣做效率會得到很大的提升。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387473.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387473.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387473.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2.5 map

#include<map> key/value對 采用紅黑樹實現&#xff0c;鍵值不允許重復 用法與set類似 創建map&#xff1a; map<string, float> m; m["haha"] 11.1; m["hehe"] 22.2; for (map<string, float>::iterator it m.begin(); it ! m.en…

在js傳遞參數中含加號(+)的處理方式

一般情況下&#xff0c;url中的參數應使用 url 編碼規則&#xff0c;即把參數字符串中除了 “ - "、" _ " 、" . "之外的所有非字母數字字符都將被替換成百分號&#xff08;%&#xff09;后跟兩位十六進制數&#xff0c;空格則編碼為加號&#xff08;…

二 SVN代碼沖突的解決

問題&#xff1a; A和B都是最新的代碼&#xff0c;A修改了代碼提交了&#xff0c;B也修改了代碼&#xff0c;但是B提交的時候出現沖突的問題。 解決方案&#xff1a;編輯沖突 解決沖突&#xff1a; 方法一&#xff1a;將文件里面沖突的描述去掉&#xff0c;重新提交 方法二&…

Android7.0反射類找不到的問題

Java中使用反射的地方較多&#xff0c;尤其是各種框架中。最近在Android7.0的項目中遇到個問題很奇怪&#xff0c;反射使用的類找不到了&#xff0c;但是編譯的時候沒問題啊。然后在代碼中使用非反射的方式調用代碼也是沒有問題的&#xff0c;這時奇怪的現象出現了&#xff0c;…

2.6 multimap

#include<map> multimap的元素插入、刪除、查找與map不同 multimap元素的插入&#xff1a;&#xff08;未提供mm[key]value插入方式&#xff09; multimap<string, double> mm; mm.insert(pair<string, double>("haha", 11.1)); mm.insert(pai…

Mybatis學習筆記18 - 緩存

兩級緩存&#xff1a; 一級緩存&#xff1a;&#xff08;本地緩存&#xff09;&#xff1a;sqlSession級別的緩存。一級緩存是一直開啟的&#xff1b;SqlSession級別的一個Map 數據庫同一次會話期間查詢到的數據會放在本地緩存中。以后如果需要獲取相同的數據&#xff0c;直接從…

2.7 deque

#include<deque> 雙端隊列容器 注意&#xff1a;頭入隊時伴隨的是尾出隊&#xff1b;提供中間元素的更新和刪除操作。 與vector一樣&#xff0c;采用線性表順序存儲結構 deque采用分塊的線性存儲結構來存儲數據&#xff0c;每塊大小一般為512字節 所有deque塊由一個…

APK 加殼方法

下載工具http://download.csdn.net/download/sys025/8958363一款免費的為apk加固的工具。 特別說明&#xff1a;加固后需要重新簽名apk才能安裝。加固的apk包會比未加固的大一些。 jarsigner -verbose -keystore dms.keystore -storepass pactera -keypass pactera -sigfile CE…

Java DSL簡介(收集整理)

一、領域特定語言&#xff08;DSL&#xff09; 領域特定語言&#xff08;DSL&#xff09;通常被定義為一種特別針對某類特殊問題的計算機語言&#xff0c;它不打算解決其領域外的問題。對于DSL的正式研究已經持續很多年&#xff0c;直 到最近&#xff0c;在程序員試圖采用最易讀…

[轉]JSon數據解析的四種方式

轉至http://blog.csdn.net/enuola/article/details/7903632 作為一種輕量級的數據交換格式&#xff0c;json正在逐步取代xml&#xff0c;成為網絡數據的通用格式。 有的json代碼格式比較混亂&#xff0c;可以使用此“http://www.bejson.com/”網站來進行JSON格式化校驗&#xf…

2.8 list

#include<list> 雙向循環鏈表 list結點的三個域&#xff1a;數據域、前驅元素指針域、后繼元素指針域 對于list的迭代器&#xff0c;只有或--的操作&#xff0c;無n或-n的操作 創建list對象&#xff1a; list<int> l; list<int> l(10); 插入和遍歷&…

Spring AOP兩種實現機制是什么?

Spring AOP兩種實現機制是什么&#xff1f; 1.如果是有接口聲明的類進行AOP 時&#xff0c;spring調用的是java.lang.reflection.Proxy 類來做處理 2.如果是沒有接口聲明的類時&#xff0c; spring通過cglib包和內部類來實現 在AOP&#xff0c;權限控制&#xff0c;事務管理等…

iOS開發UI篇—Quartz2D使用(繪圖路徑)

1 //1.獲取圖形上下文 2 CGContextRef ctxUIGraphicsGetCurrentContext(); 3 //2.繪圖&#xff08;畫線&#xff09; 4 //設置起點 5 CGContextMoveToPoint(ctx, 20, 20); 6 //設置終點 7 CGContextAddLineToPoint(ctx, 200, 300); 8 //渲染 9…

2.9 bitset

#include<bitset> bitset容器是一個bit位元素的序列容器&#xff0c;每個元素只占一個bit位&#xff0c;取值為0或1&#xff0c;因而很節省內存空間。 bitset<n> b; b.any() 是否有1 b.none() 是否無1 b.count() 1的個數 b.size() 大小 b[pos] 訪問 b.…

C# 談談Interface和通過Interface傳遞web頁面數據

接口&#xff1a;描述可屬于任何類或結構的一組相關功能&#xff0c;通過interface關鍵字來聲明&#xff1b;接口只包含方法、委托或事件和屬性的簽名&#xff08;接口包含的成員&#xff09;、不能包含字段&#xff08;因為字段是包含數據的&#xff09;。方法的實現是“繼承”…

Spring支持如下5種作用域

當通過Spring容器創建一個Bean實例時&#xff0c;不僅可以完成Bean實例的實例化&#xff0c;還可以為Bean指定特定的作用域。Spring支持如下5種作用域&#xff1a; singleton&#xff1a;單例模式&#xff0c;在整個Spring IoC容器中&#xff0c;使用singleton定義的Bean將只有…

RBAC授權

給用戶授予RBAC權限沒有權限會報如下錯誤&#xff1a;執行查看資源報錯&#xff1a; unable to upgrade connection: Forbidden (userkubernetes, verbcreate, resourcenodes, subresourceproxy)[roottest4 ~]# kubectl exec -it http-test-dm2-6dbd76c7dd-cv9qf sh error: una…

出卷子

http://chujuanzi.com/ 出卷子 涵蓋初高中全部學科題庫&#xff0c;全國名校試卷最快更新。試卷新、試題全、解析準、完全免費&#xff0c;提供豐富試題輔助教師有效出試卷&#xff0c;組卷方便快捷。&#xff08;高中語文 高中數學 高中英語 高中物理 高中化學 高中生物 高中政…

2.10 stack

#include<stack> 后進先出 Last In First Out LIFO 插入和刪除元素只能在表的一端進行。 插入端 棧頂 Stack Top 入棧 Push 刪除端 棧底 Stack Bottom 出棧 Pop stack<int> s; s.push(1); //入棧 int i s.top(); //獲得棧頂元素 s.pop(); //出棧 s.size…

13結構型模式之橋接模式

概念 Bridge 模式又叫做橋接模式&#xff0c;是構造型的設計模式之一。Bridge模式基于類的最小設計原則&#xff0c;通過使用封裝&#xff0c;聚合以及繼承等行為來讓不同的類承擔不同的責任。它的主要特點是把抽象&#xff08;abstraction&#xff09;與行為實現&#xff08;i…