日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
用Java.nio.*進(jìn)行網(wǎng)絡(luò)編程

前言

10余年的科爾沁左翼網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整科爾沁左翼建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)建站從事“科爾沁左翼網(wǎng)站設(shè)計(jì)”,“科爾沁左翼網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

因?yàn)榇蛩阌胘ava編寫異步通信的server和client程序,筆者便學(xué)習(xí)使用java.nio開發(fā)包,其間遇到一些問題,上網(wǎng)卻發(fā)現(xiàn)網(wǎng)上對它的應(yīng)用描述的不是很多。所以,筆者不惜班門弄斧,做些簡單的討論,以便大家更進(jìn)一步的討論。

對相關(guān)類的簡單介紹

java.nio.*, 據(jù)說它提供了一些更加底層的一些功能,如:類似windows環(huán)境下的AsyncSocket類的異步操作的功能,能顯著降低server端程序的線程管理開銷。

因?yàn)榇蠖鄶?shù)應(yīng)用是建立在TCP之上,所以在此只說說SocketChannel,ServerSocketChannel,Selector 和ByteBuffer這幾個(gè)類.前三個(gè)最終都源自channel類。而channel 類,可以理解為在具體I/O或文件對象之上抽象的一個(gè)操作對象,我們通過操作channel的讀寫達(dá)到對其對應(yīng)的文件或I/O對象(包括socket)讀寫的目的。讀寫的內(nèi)容在內(nèi)存中放在ByteBuffer類提供的緩沖區(qū)??偠灾琧hannel作為一個(gè)橋梁,連接了I/O對象和內(nèi)存中的 ByteBuffer,實(shí)現(xiàn)了I/O的更高效的存取。

一個(gè)基于TCP的服務(wù)器端程序,必然有個(gè)偵聽端和若干個(gè)通信端,它們在nio中由對應(yīng)的ServerSocketChannel 和SocketChannel類來實(shí)現(xiàn)。為了達(dá)到異步I/O操作的目的,需要Selector類,它能檢測到I/O對象的狀態(tài)。

SocketChannel類是抽象類,通過調(diào)用它的靜態(tài)函數(shù)open(),可生成一個(gè)SocketChannel對象,該對象對應(yīng)一個(gè)java.net.Socket,可通過SocketChannel.socket()獲得,而其對應(yīng)的Socket也可通過調(diào)用函數(shù)getChannel()得到已建立的相應(yīng)SocketChannel。

SocketChannel與它的socket是一一對應(yīng)的。SocketChannel的操作與Socket也很相似。

ServerSocketChannel也是通過調(diào)用它的靜態(tài)函數(shù)open()生成的,只是它不能直接調(diào)用bind()函數(shù)來綁定一個(gè)地址,需要它對應(yīng)的ServerSocket來完成綁定工作,一般可按如下步驟做:

 
 
 
  1. ServerSocketChannel ssc = new ServerSocketChannel.open(); 
  2. ssc.socket().bind(InetSocketAddress(host,port)); 

羅嗦了半天,還是看看最簡單的C/S實(shí)現(xiàn)吧,服務(wù)器提供了基本的回射(echo)功能,其中提供了較詳細(xì)的注釋。

源碼分析

1.服務(wù)器端:

 
 
 
  1. //////////////////////// 
  2. //AsyncServer.java 
  3. // by zztudou@163.com 
  4. //////////////////////// 
  5. import java.nio.channels.SocketChannel; 
  6. import java.nio.channels.ServerSocketChannel; 
  7. import java.nio.channels.SelectionKey; 
  8. import java.nio.channels.Selector; 
  9. import java.nio.ByteBuffer; 
  10. import java.nio.channels.SelectableChannel; 
  11. import java.nio.channels.spi.SelectorProvider; 
  12. import java.net.ServerSocket; 
  13. import java.net.Socket; 
  14. import java.net.InetSocketAddress; 
  15. import java.net.SocketAddress; 
  16. import java.util.Iterator; 
  17. import java.util.LinkedList; 
  18. import java.io.IOException; 
  19.  
  20. class AsyncServer implements Runnable{  
  21. private ByteBuffer r_buff = ByteBuffer.allocate(1024); 
  22. private ByteBuffer w_buff = ByteBuffer.allocate(1024); 
  23. private static int port = 8848; 
  24.  
  25. public AsyncServer(){ 
  26. new Thread(this).start(); 
  27.  
  28. public void run(){  
  29. try{ 
  30. //生成一個(gè)偵聽端 
  31. ServerSocketChannel ssc = ServerSocketChannel.open(); 
  32. //將偵聽端設(shè)為異步方式 
  33. ssc.configureBlocking(false); 
  34. //生成一個(gè)信號監(jiān)視器 
  35. Selector s = Selector.open(); 
  36. //偵聽端綁定到一個(gè)端口 
  37. ssc.socket().bind(new InetSocketAddress(port)); 
  38. //設(shè)置偵聽端所選的異步信號OP_ACCEPT 
  39. ssc.register(s,SelectionKey.OP_ACCEPT); 
  40.  
  41. System.out.println("echo server has been set up ......"); 
  42.  
  43. while(true){ 
  44. int n = s.select(); 
  45. if (n == 0) {//沒有指定的I/O事件發(fā)生 
  46. continue; 
  47. }  
  48. Iterator it = s.selectedKeys().iterator();  
  49. while (it.hasNext()) { 
  50. SelectionKey key = (SelectionKey) it.next(); 
  51. if (key.isAcceptable()) {//偵聽端信號觸發(fā) 
  52. ServerSocketChannel server = (ServerSocketChannel) key.channel(); 
  53. //接受一個(gè)新的連接 
  54. SocketChannel sc = server.accept(); 
  55. sc.configureBlocking(false); 
  56. //設(shè)置該socket的異步信號OP_READ:當(dāng)socket可讀時(shí), 
  57.  
  58. //觸發(fā)函數(shù)DealwithData(); 
  59. sc.register(s,SelectionKey.OP_READ); 
  60. }  
  61. if (key.isReadable()) {//某socket可讀信號 
  62. DealwithData(key); 
  63. }  
  64. it.remove(); 
  65. catch(Exception e){ 
  66. e.printStackTrace();  
  67.  
  68. public void DealwithData(SelectionKey key) throws IOException{ 
  69. int count; 
  70. //由key獲取指定socketchannel的引用 
  71. SocketChannel sc = (SocketChannel)key.channel(); 
  72. r_buff.clear(); 
  73. //讀取數(shù)據(jù)到r_buff 
  74. while((count = sc.read(r_buff))> 0) 
  75. //確保r_buff可讀 
  76. r_buff.flip(); 
  77.  
  78. w_buff.clear(); 
  79. //將r_buff內(nèi)容拷入w_buff  
  80. w_buff.put(r_buff); 
  81. w_buff.flip(); 
  82. //將數(shù)據(jù)返回給客戶端 
  83. EchoToClient(sc); 
  84.  
  85. w_buff.clear(); 
  86. r_buff.clear(); 
  87.  
  88. public void EchoToClient(SocketChannel sc) throws IOException{ 
  89. while(w_buff.hasRemaining()) 
  90. sc.write(w_buff); 
  91.  
  92. public static void main(String args[]){ 
  93. if(args.length > 0){ 
  94. port = Integer.parseInt(args[0]); 
  95. new AsyncServer(); 

在當(dāng)前目錄下運(yùn)行:

javac AsynServer.java

后,若無編譯出錯(cuò),接下來可運(yùn)行:

java AsynServer 或 java AsynServer ×××(端口號)

上述服務(wù)程序在運(yùn)行時(shí),可指定其偵聽端口,否則程序會(huì)取8848為默認(rèn)端口。

2.客戶端的簡單示例:

 
 
 
  1. //////////////////////// 
  2. //AsyncClient.java 
  3. // by zztudou@163.com 
  4. //////////////////////// 
  5. import java.nio.channels.SocketChannel; 
  6. import java.net.InetSocketAddress; 
  7. import java.nio.ByteBuffer; 
  8. import java.nio.channels.Selector; 
  9. import java.nio.channels.SelectionKey; 
  10.  
  11. import java.io.IOException; 
  12. import java.io.BufferedReader; 
  13. import java.io.InputStreamReader; 
  14.  
  15. class AsyncClient{ 
  16. private SocketChannel sc; 
  17. private final int MAX_LENGTH = 1024; 
  18. private ByteBuffer r_buff = ByteBuffer.allocate(MAX_LENGTH); 
  19. private ByteBuffer w_buff = ByteBuffer.allocate(MAX_LENGTH); 
  20. private static String host ; 
  21. private static int port = 8848; 
  22.  
  23. public AsyncClient(){ 
  24. try { 
  25. InetSocketAddress addr = new InetSocketAddress(host,port); 
  26. //生成一個(gè)socketchannel 
  27. sc = SocketChannel.open(); 
  28.  
  29. //連接到server 
  30. sc.connect(addr); 
  31. while(!sc.finishConnect()) 
  32. ;  
  33. System.out.println("connection has been established!..."); 
  34.  
  35. while(true){ 
  36. //回射消息 
  37. String echo; 
  38. try{ 
  39. System.err.println("Enter msg you'd like to send: "); 
  40. BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
  41. //輸入回射消息 
  42. echo = br.readLine(); 
  43.  
  44. //把回射消息放入w_buff中  
  45. w_buff.clear(); 
  46. w_buff.put(echo.getBytes()); 
  47. w_buff.flip(); 
  48. }catch(IOException ioe){ 
  49. System.err.println("sth. is wrong with br.readline() "); 
  50. }  
  51.  
  52. //發(fā)送消息 
  53. while(w_buff.hasRemaining()) 
  54. sc.write(w_buff); 
  55. w_buff.clear();  
  56.  
  57. //進(jìn)入接收狀態(tài) 
  58. Rec(); 
  59. //間隔1秒 
  60. Thread.currentThread().sleep(1000); 
  61. }  
  62. }catch(IOException ioe){ 
  63. ioe.printStackTrace(); 
  64. catch(InterruptedException ie){ 
  65. ie.printStackTrace(); 
  66. }  
  67. //////////// 
  68. //讀取server端發(fā)回的數(shù)據(jù),并顯示 
  69. public void Rec() throws IOException{ 
  70. int count; 
  71. r_buff.clear();  
  72. count=sc.read(r_buff); 
  73. r_buff.flip();  
  74. byte[] temp = new byte[r_buff.limit()]; 
  75. r_buff.get(temp); 
  76. System.out.println("reply is " + count +" long, and content is: " + new String(temp)); 
  77.  
  78. public static void main(String args[]){ 
  79. if(args.length < 1){//輸入需有主機(jī)名或IP地址 
  80. try{ 
  81. System.err.println("Enter host name: "); 
  82. BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 
  83. host = br.readLine(); 
  84. }catch(IOException ioe){ 
  85. System.err.println("sth. is wrong with br.readline() "); 
  86. else if(args.length == 1){ 
  87. host = args[0]; 
  88. else if(args.length > 1){ 
  89. host = args[0]; 
  90. port = Integer.parseInt(args[1]); 
  91.  
  92. new AsyncClient(); 

在當(dāng)前目錄下運(yùn)行:

javac AsynClient.java

后,若無編譯出錯(cuò),確認(rèn)AsyncServer已經(jīng)運(yùn)行的情況下,接下來可運(yùn)行:

java AsynClient hostname 或 java AsynClient hostname ×××(端口號)

并按提示進(jìn)行操作即可。

總 結(jié)

總的來說,用nio進(jìn)行網(wǎng)絡(luò)編程還是很有新意的,服務(wù)器端軟件能在一個(gè)線程中維護(hù)與眾多客戶端的通信連接。筆者在本文中試圖用一個(gè)典型的回射例子說明如何用nio建立最基本的C/S應(yīng)用。希望大家能試著用用它。
另外,筆者在實(shí)踐中也發(fā)現(xiàn)nio在應(yīng)用中存在的一些難題,比如如何應(yīng)用SocketChannel的繼承類,以及如何在socketchannel之上應(yīng)用SSL(Secure Socket Layer)等等,因而希望這篇文章只是拋磚引玉,引起大家對nio作進(jìn)一步的討論。

原文鏈接:http://lrtlcg.iteye.com/blog/844357

【編輯推薦】

  1. Java NIO的wakeup剖析
  2. Java NIO類庫關(guān)系圖解
  3. 淺析Tomcat NIO 配置
  4. Java NIO API詳解
  5. Java NIO基本使用實(shí)例

分享標(biāo)題:用Java.nio.*進(jìn)行網(wǎng)絡(luò)編程
文章鏈接:http://www.dlmjj.cn/article/djcjpeh.html