成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基于事件的NIO多線程服務(wù)器

開發(fā) 后端
JDK1.4的NIO有效解決了原有流式IO存在的線程開銷的問(wèn)題,在NIO中使用多線程,主要目的已不是為了應(yīng)對(duì)每個(gè)客戶端請(qǐng)求而分配獨(dú)立的服務(wù)線程,而是通過(guò)多線程充分使用用多個(gè)CPU的處理能力和處理中的等待時(shí)間,達(dá)到提高服務(wù)能力的目的。

JDK1.4的NIO有效解決了原有流式IO存在的線程開銷的問(wèn)題,在NIO中使用多線程,主要目的已不是為了應(yīng)對(duì)每個(gè)客戶端請(qǐng)求而分配獨(dú)立的服務(wù)線程,而是通過(guò)多線程充分使用用多個(gè)CPU的處理能力和處理中的等待時(shí)間,達(dá)到提高服務(wù)能力的目的。

線程模型

NIO的選擇器采用了多路復(fù)用(Multiplexing)技術(shù),可在一個(gè)選擇器上處理多個(gè)套接字,通過(guò)獲取讀寫通道來(lái)進(jìn)行IO操作。由于網(wǎng)絡(luò)帶寬等原因,在通道的讀、寫操作中是容易出現(xiàn)等待的,所以在讀、寫操作中引入多線程,對(duì)性能提高明顯,而且可以提高客戶端的感知服務(wù)質(zhì)量。所以本文的模型將主要通過(guò)使用讀、寫線程池來(lái)提高與客戶端的數(shù)據(jù)交換能力。

同時(shí)整個(gè)服務(wù)端的流程處理,建立于事件機(jī)制上。在 [接受連接->讀->業(yè)務(wù)處理->寫 ->關(guān)閉連接 ]這個(gè)過(guò)程中,觸發(fā)器將觸發(fā)相應(yīng)事件,由事件處理器對(duì)相應(yīng)事件分別響應(yīng),完成服務(wù)器端的業(yè)務(wù)處理。
下面我們就來(lái)詳細(xì)看一下這個(gè)模型的各個(gè)組成部分。

相關(guān)事件定義 在這個(gè)模型中,我們定義了一些基本的事件:

(1)onAccept:

當(dāng)服務(wù)端收到客戶端連接請(qǐng)求時(shí),觸發(fā)該事件。通過(guò)該事件我們可以知道有新的客戶端呼入。該事件可用來(lái)控制服務(wù)端的負(fù)載。例如,服務(wù)器可設(shè)定同時(shí)只為一定數(shù)量客戶端提供服務(wù),當(dāng)同時(shí)請(qǐng)求數(shù)超出數(shù)量時(shí),可在響應(yīng)該事件時(shí)直接拋出異常,以拒絕新的連接。

(2)onAccepted:

當(dāng)客戶端請(qǐng)求被服務(wù)器接受后觸發(fā)該事件。該事件表明一個(gè)新的客戶端與服務(wù)器正式建立連接。

(3)onRead:

當(dāng)客戶端發(fā)來(lái)數(shù)據(jù),并已被服務(wù)器控制線程正確讀取時(shí),觸發(fā)該事件。該事件通知各事件處理器可以對(duì)客戶端發(fā)來(lái)的數(shù)據(jù)進(jìn)行實(shí)際處理了。需要注意的是,在本模型中,客戶端的數(shù)據(jù)讀取是由控制線程交由讀線程完成的,事件處理器不需要在該事件中進(jìn)行專門的讀操作,而只需將控制線程傳來(lái)的數(shù)據(jù)進(jìn)行直接處理即可。

(4)onWrite:

當(dāng)客戶端可以開始接受服務(wù)端發(fā)送數(shù)據(jù)時(shí)觸發(fā)該事件,通過(guò)該事件,我們可以向客戶端發(fā)送回應(yīng)數(shù)據(jù)。在本模型中,事件處理器只需要在該事件中設(shè)置 。

(5)onClosed:

當(dāng)客戶端與服務(wù)器斷開連接時(shí)觸發(fā)該事件。

(6)onError:

當(dāng)客戶端與服務(wù)器從連接開始到***斷開連接期間發(fā)生錯(cuò)誤時(shí)觸發(fā)該事件。通過(guò)該事件我們可以知道有什么錯(cuò)誤發(fā)生。

事件回調(diào)機(jī)制的實(shí)現(xiàn)

在這個(gè)模型中,事件采用廣播方式,也就是所有在冊(cè)的事件處理器都能獲得事件通知。這樣可以將不同性質(zhì)的業(yè)務(wù)處理,分別用不同的處理器實(shí)現(xiàn),使每個(gè)處理器的業(yè)務(wù)功能盡可能單一。

如下圖:整個(gè)事件模型由監(jiān)聽器、事件適配器、事件觸發(fā)器、事件處理器組成。

(事件模型)

1.監(jiān)聽器(Serverlistener):

這是一個(gè)事件接口,定義需監(jiān)聽的服務(wù)器事件,如果您需要定義更多的事件,可在這里進(jìn)行擴(kuò)展。

  1. public interface Serverlistener  
  2. public void onError(String error); 
  3. public void onAccept() throws Exception; 
  4. public void onAccepted(Request request) throws Exception; 
  5. public void onRead(Request request) throws Exception; 
  6. public void onWrite(Request request, Response response) throws Exception; 
  7. public void onClosed(Request request) throws Exception; 

2. 事件適配器(EventAdapter):

對(duì)Serverlistener接口實(shí)現(xiàn)一個(gè)適配器(EventAdapter),這樣的好處是最終的事件處理器可以只處理所關(guān)心的事件。

  1. public abstract class EventAdapter  
  2. implements Serverlistener  
  3. public EventAdapter() {} 
  4. public void onError(String error) {} 
  5. public void onAccept() throws Exception {} 
  6. public void onAccepted(Request request) throws Exception {} 
  7. public void onRead(Request request) throws Exception {} 
  8. public void onWrite(Request request, Response response) throws Exception {} 
  9. public void onClosed(Request request) throws Exception {} 

3. 事件觸發(fā)器(Notifier):

用于在適當(dāng)?shù)臅r(shí)候通過(guò)觸發(fā)服務(wù)器事件,通知在冊(cè)的事件處理器對(duì)事件做出響應(yīng)。觸發(fā)器以Singleton模式實(shí)現(xiàn),統(tǒng)一控制整個(gè)服務(wù)器端的事件,避免造成混亂。

  1. public class Notifier  
  2. private static Arraylist listeners = null
  3. private static Notifier instance = null
  4.  
  5. private Notifier()  
  6. listeners = new Arraylist(); 
  7.  
  8. /** 
  9. * 獲取事件觸發(fā)器 
  10. * @return 返回事件觸發(fā)器 
  11. */ 
  12. public static synchronized Notifier  
  13. getNotifier()  
  14. if (instance == null)  
  15. instance = new Notifier(); 
  16. return instance; 
  17. else  
  18. return instance; 
  19.  
  20. /** 
  21. * 添加事件監(jiān)聽器 
  22. * @param l 監(jiān)聽器 
  23. */ 
  24. public void addlistener(Serverlistener l) 
  25. synchronized (listeners) 
  26. if (!listeners.contains(l)) 
  27. listeners.add(l); 
  28.  
  29. public void fireOnAccept()  
  30. throws Exception  
  31. for (int i = listeners.size() - 1;  
  32. i >= 0; i--) 
  33. ( (Serverlistener) listeners. 
  34. get(i)).onAccept(); 
  35. // other fire method 

4. 事件處理器(Handler):

繼承事件適配器,對(duì)感興趣的事件進(jìn)行響應(yīng)處理,實(shí)現(xiàn)業(yè)務(wù)處理。以下是一個(gè)簡(jiǎn)單的事件處理器實(shí)現(xiàn),它響應(yīng)onRead事件,在終端打印出從客戶端讀取的數(shù)據(jù)。

  1. public class ServerHandler  
  2. extends EventAdapter  
  3. public ServerHandler() {} 
  4.  
  5. public void onRead(Request request)  
  6. throws Exception  
  7. System.out.println("Received: " + 
  8. new String(data)); 

5. 事件處理器的注冊(cè)。

為了能讓事件處理器獲得服務(wù)線程的事件通知,事件處理器需在觸發(fā)器中注冊(cè)。

  1. ServerHandler handler = new ServerHandler(); 
  2. Notifier.addlistener(handler); 

實(shí)現(xiàn)NIO多線程服務(wù)器

NIO多線程服務(wù)器主要由主控服務(wù)線程、讀線程和寫線程組成。

1. 主控服務(wù)線程(Server):

主控線程將創(chuàng)建讀、寫線程池,實(shí)現(xiàn)監(jiān)聽、接受客戶端請(qǐng)求,同時(shí)將讀、寫通道提交由相應(yīng)的讀線程(Reader)和寫服務(wù)線程(Writer),由讀寫線程分別完成對(duì)客戶端數(shù)據(jù)的讀取和對(duì)客戶端的回應(yīng)操作。

  1. public class Server implements Runnable 
  2. private static List wpool = new LinkedList();  
  3. private static Selector selector; 
  4. private ServerSocketChannel sschannel; 
  5. private InetSocketAddress address; 
  6. protected Notifier notifier; 
  7. private int port; 
  8. private static int MAX_THREADS = 4
  9.  
  10. /** 
  11. * Creat the main thread 
  12. * @param port server port 
  13. * @throws java.lang.Exception 
  14. */ 
  15. public Server(int port) throws Exception 
  16. this.port = port; 
  17.  
  18. // event dispatcher 
  19. notifier = Notifier.getNotifier(); 
  20.  
  21. // create the thread pool for reading and writing 
  22. for (int i = 0; i < MAX_THREADS; i++) 
  23. Thread r = new Reader(); 
  24. Thread w = new Writer(); 
  25. r.start(); 
  26. w.start(); 
  27.  
  28. // create nonblocking socket 
  29. selector = Selector.open(); 
  30. sschannel = ServerSocketChannel.open(); 
  31. sschannel.configureBlocking(false); 
  32. address = new InetSocketAddress(port); 
  33. ServerSocket ss = sschannel.socket(); 
  34. ss.bind(address); 
  35. sschannel.register(selector, SelectionKey.OP_ACCEPT); 
  36.  
  37. public void run() 
  38. System.out.println("Server started "); 
  39. System.out.println("Server listening on port: " + port); 
  40.  
  41. while (true
  42. try 
  43. int num = 0
  44. num = selector.select(); 
  45.  
  46. if (num > 0
  47. Set selectedKeys = selector.selectedKeys(); 
  48. Iterator it = selectedKeys.iterator(); 
  49. while (it.hasNext()) 
  50. SelectionKey key = (SelectionKey) it.next(); 
  51. it.remove(); 
  52.  
  53. if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) 
  54. // Accept the new connection 
  55. ServerSocketChannel ssc =  
  56. (ServerSocketChannel) key.channel(); 
  57. notifier.fireOnAccept(); 
  58.  
  59. SocketChannel sc = ssc.accept(); 
  60. sc.configureBlocking(false); 
  61.  
  62. Request request = new Request(sc); 
  63. notifier.fireOnAccepted(request); 
  64.  
  65. sc.register(selector, SelectionKey.OP_READ,request); 
  66. }  
  67. else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) 
  68. Reader.processRequest(key);  
  69. key.cancel(); 
  70. }  
  71. else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) 
  72. Writer.processRequest(key); 
  73. key.cancel(); 
  74. }  
  75. //this selector's wakeup method is invoked 
  76. else 
  77. //register new channel for writing to selector 
  78. addRegister();  
  79. }  
  80. catch (Exception e) 
  81. notifier.fireOnError("Error occured in Server: " 
  82. + e.getMessage()); 
  83. continue
  84.  
  85. private void addRegister() 
  86. synchronized (wpool) 
  87. while (!wpool.isEmpty()) 
  88. SelectionKey key = (SelectionKey) wpool.remove(0); 
  89. SocketChannel schannel = (SocketChannel) key.channel(); 
  90. try 
  91. schannel.register(selector, SelectionKey.OP_WRITE, key 
  92. .attachment()); 
  93. catch (Exception e) 
  94. try 
  95. schannel.finishConnect(); 
  96. schannel.close(); 
  97. schannel.socket().close(); 
  98. notifier.fireOnClosed((Request) key.attachment()); 
  99. }  
  100. catch (Exception e1) 
  101. notifier.fireOnError("Error occured in addRegister: " 
  102. + e.getMessage()); 
  103.  
  104. public static void processWriteRequest(SelectionKey key) 
  105. synchronized (wpool) 
  106. wpool.add(wpool.size(), key); 
  107. wpool.notifyAll(); 
  108. selector.wakeup();  

2. 讀線程(Reader):

使用線程池技術(shù),通過(guò)多個(gè)線程讀取客戶端數(shù)據(jù),以充分利用網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)臅r(shí)間,提高讀取效率。

  1. public class Reader extends Thread  
  2. public void run()  
  3. while (true)  
  4. try  
  5. SelectionKey key; 
  6. synchronized (pool)  
  7. while (pool.isEmpty())  
  8. pool.wait(); 
  9. key = (SelectionKey) pool.remove(0); 
  10. // 讀取客戶端數(shù)據(jù),并觸發(fā)onRead事件 
  11. read(key);  
  12. catch (Exception e)  
  13. continue

3. 寫線程(Writer):

和讀操作一樣,使用線程池,負(fù)責(zé)將服務(wù)器端的數(shù)據(jù)發(fā)送回客戶端。

  1. public final class Writer extends Thread  
  2. public void run()  
  3. while (true)  
  4. try  
  5. SelectionKey key; 
  6. synchronized (pool)  
  7. while (pool.isEmpty())  
  8. pool.wait(); 
  9. key = (SelectionKey) pool.remove(0); 
  10.  
  11. write(key);  
  12. catch (Exception e)  
  13. continue

具體應(yīng)用

NIO多線程模型的實(shí)現(xiàn)告一段落,現(xiàn)在我們可以暫且將NIO的各個(gè)API和煩瑣的調(diào)用方法拋于腦后,專心于我們的實(shí)際應(yīng)用中。

我們用一個(gè)簡(jiǎn)單的TimeServer(時(shí)間查詢服務(wù)器)來(lái)看看該模型能帶來(lái)多么簡(jiǎn)潔的開發(fā)方式。

在這個(gè)TimeServer中,將提供兩種語(yǔ)言(中文、英文)的時(shí)間查詢服務(wù)。我們將讀取客戶端的查詢命令(GB/EN),并回應(yīng)相應(yīng)語(yǔ)言格式的當(dāng)前時(shí)間。在應(yīng)答客戶的請(qǐng)求的同時(shí),服務(wù)器將進(jìn)行日志記錄。做為示例,對(duì)日志記錄,我們只是簡(jiǎn)單地將客戶端的訪問(wèn)時(shí)間和IP地址輸出到服務(wù)器的終端上。

1. 實(shí)現(xiàn)時(shí)間查詢服務(wù)的事件處理器(TimeHandler):

  1. public class TimeHandler extends EventAdapter  
  2. public TimeHandler() {} 
  3.  
  4. public void onWrite(Request request, Response response) throws Exception  
  5. String command = new String(request.getDataInput()); 
  6. String time = null
  7. Date date = new Date(); 
  8.  
  9. if (command.equals("GB"))  
  10. DateFormat cnDate = DateFormat.getDateTimeInstance(DateFormat.FulL, 
  11. DateFormat.FulL, Locale.CHINA); 
  12. time = cnDate.format(date); 
  13. else  
  14. DateFormat enDate = DateFormat.getDateTimeInstance(DateFormat.FulL, 
  15. DateFormat.FulL, Locale.US); 
  16. time = enDate.format(date); 
  17.  
  18. response.send(time.getBytes()); 

2. 實(shí)現(xiàn)日志記錄服務(wù)的事件處理器(LogHandler):

  1. public class LogHandler extends EventAdapter  
  2. public LogHandler() {} 
  3.  
  4. public void onClosed(Request request)  
  5. throws Exception  
  6. String log = new Date().toString() + " from " + request.getAddress().toString(); 
  7. System.out.println(log); 
  8.  
  9. public void onError(String error)  
  10. System.out.println("Error: " + error); 

3. 啟動(dòng)程序:

  1. public class Start  
  2.  
  3. public static void main(String[] args)  
  4. try  
  5. LogHandler loger = new LogHandler(); 
  6. TimeHandler timer = new TimeHandler(); 
  7. Notifier notifier = Notifier.getNotifier(); 
  8. notifier.addlistener(loger); 
  9. notifier.addlistener(timer); 
  10.  
  11. System.out.println("Server starting "); 
  12. Server server = new Server(5100); 
  13. Thread tServer = new Thread(server); 
  14. tServer.start(); 
  15. catch (Exception e)  
  16. System.out.println("Server error: " + e.getMessage()); 
  17. System.exit(-1); 

小  結(jié)

通過(guò)例子我們可以看到,基于事件回調(diào)的NIO多線程服務(wù)器模型,提供了清晰直觀的實(shí)現(xiàn)方式,可讓開發(fā)者從NIO及多線程的技術(shù)細(xì)節(jié)中擺脫出來(lái),集中精力關(guān)注具體的業(yè)務(wù)實(shí)現(xiàn)。

原文鏈接:http://www.cnblogs.com/longb/archive/2006/04/04/366800.html

【編輯推薦】

  1. Java NIO的多路復(fù)用及reactor
  2. 在Java中使用NIO進(jìn)行網(wǎng)絡(luò)編程
  3. Java NIO非阻塞服務(wù)器示例
  4. 基于Java NIO的即時(shí)聊天服務(wù)器模型
  5. Java解讀NIO Socket非阻塞模式
責(zé)任編輯:林師授 來(lái)源: 涇溪的博客
相關(guān)推薦

2011-12-08 09:37:36

JavaNIO

2009-02-27 11:15:00

多線程服務(wù)器MTS專用服務(wù)器

2009-02-18 10:41:16

多線程服務(wù)器穩(wěn)定Java

2011-12-07 17:05:45

JavaNIO

2010-03-17 17:54:25

java Socket

2010-03-19 14:01:55

Java Socket

2018-12-20 09:36:24

2011-06-30 18:03:58

QT 多線程 服務(wù)器

2011-12-08 10:12:34

JavaNIO

2011-12-15 11:03:21

JavaNIO

2010-03-16 10:50:21

Java多線程服務(wù)器

2011-03-11 09:51:47

Java NIO

2015-10-27 09:40:31

TCPIP網(wǎng)絡(luò)協(xié)議

2010-03-16 13:47:48

Java多線程服務(wù)器

2018-11-28 09:53:50

游戲服務(wù)器線程

2011-07-01 10:35:20

QT 多線程 TCP

2021-06-29 07:47:23

多線程協(xié)作數(shù)據(jù)

2023-05-10 10:35:14

服務(wù)器代碼

2018-01-11 08:24:45

服務(wù)器模型詳解

2009-12-07 10:25:52

服務(wù)器安全服務(wù)器事件查看器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 在线看免费的a | 超碰91在线 | 国产黄色网址在线观看 | 四虎免费视频 | 国产精品99久久久精品免费观看 | 久久久久亚洲精品中文字幕 | 精品国产乱码久久久久久牛牛 | 在线观看av中文字幕 | 欧美一区二区三区视频 | 美人の美乳で授乳プレイ | 国产区视频在线观看 | 精品无码久久久久久国产 | 免费在线成人 | 午夜男人天堂 | 成年人免费看 | www.yw193.com| 香蕉久久久 | 涩涩视频网站在线观看 | 米奇成人网 | 精品自拍视频 | 三级在线视频 | 日韩一区在线视频 | 欧美一级片黄色 | 涩涩视频在线播放 | 精品国产一区久久 | 国产精品揄拍一区二区 | 四虎影院在线免费观看 | 伊人超碰 | 国产精品美女久久久久久免费 | 99精品久久久久久久 | 欧美嘿咻 | 蜜桃精品视频在线 | 日本人做爰大片免费观看一老师 | 欧美日韩国产中文 | 一级黄色录像毛片 | 精产国产伦理一二三区 | 国产成人免费 | 国产98色在线 | 日韩 | 日韩在线一区二区三区 | 欧州一区二区三区 | 国产日韩精品一区 |