本文目錄一覽:
- 1、java mina 數據發送前怎樣判斷連接狀態
- 2、java mina 可以多線程寫么
- 3、java Mina伺服器 java.io.IOException: Connection reset by peer,請問怎麼解決?
- 4、java mina 怎麼打成jar包放在伺服器上呀~~
java mina 數據發送前怎樣判斷連接狀態
1 Mina基本開發知識
1.1 非阻塞模式
Java NIO非堵塞應用通常適用用在I/O讀寫等方面,我們知道,系統運行的性能瓶頸通常在I/O讀寫,包括對埠和文件的操作上,過去,在打開一個I/O通道後,read()將一直等待在埠一邊讀取位元組內容,如果沒有內容進來,read()也是傻傻的等,這會影響我們程序繼續做其他事情,那麼改進做法就是開設線程,讓線程去等待,但是這樣做也是相當耗費資源(傳統socket通訊伺服器設計模式)的。
Java NIO非堵塞技術實際是採取Reactor模式,或者說是Observer模式為我們監察I/O埠,如果有內容進來,會自動通知我們,這樣,我們就不必開啟多個線程死等,從外界看,實現了流暢的I/O讀寫,不堵塞了。
Java NIO出現不只是一個技術性能的提高,你會發現網路上到處在介紹它,因為它具有里程碑意義,從JDK1.4開始,Java開始提高性能相關的功能,從而使得Java在底層或者並行分散式計算等操作上已經可以和C或Perl等語言並駕齊驅。
如果你至今還是在懷疑Java的性能,說明你的思想和觀念已經完全落伍了,Java一兩年就應該用新的名詞來定義。從JDK1.5開始又要提供關於線程、並發等新性能的支持,Java應用在遊戲等適時領域方面的機會已經成熟,Java在穩定自己中間件地位後,開始蠶食傳統C的領域。
NIO 有一個主要的類Selector,這個類似一個觀察者,只要我們把需要探知的socketchannel告訴Selector,我們接著做別的事情,當有事件發生時,他會通知我們,傳回一組SelectionKey,我們讀取這些Key,就會獲得我們剛剛註冊過的socketchannel,然後,我們從這個Channel中讀取數據,放心,包準能夠讀到,接著我們可以處理這些數據。Selector內部原理實際是在做一個對所註冊的channel的輪詢訪問,不斷的輪詢(目前就這一個演算法),一旦輪詢到一個channel有所註冊的事情發生,比如數據來了,他就會站起來報告,交出一把鑰匙,讓我們通過這把鑰匙(SelectionKey表示 SelectableChannel 在 Selector 中的註冊的標記。 )來讀取這個channel的內容.
1.2 什麼是mian
現在已經是World Wide Web的時代,無數的web應用框架被創造出來從而大大的提高了web開發的速度。拋開WWW的這個優勢,我們知道還有很多協議是HTTP協議所無法替代的。有時,我們仍然需要構造c/s應用來實現適當的協議。
你有沒有曾經使用java或者其他語言實現過某個協議棧?就像你所經歷過的那樣,編寫網路應用即使對於有經驗的開發者也不是容易的事情。這歸咎於以下幾個方面:
* 沒有為開發者設計的合適的網路應用框架.
* 使你無法在有限的時間內創建你的應用.
* 網路I/O編碼,消息的編/解碼,業務邏輯常常糾纏在一起.
* 使程序失去可維護性和可復用性
* 網路應用難於進行單元測試
* 你失去了敏捷性
MINA是一個網路應用框架,在不犧牲性能和可擴展性的前提下用於解決上面的所有問題。
1.3 幾個介面
IoAcceptor執行所有底層IO,將他們翻譯成抽象的IO事件,並把翻譯
java mina 可以多線程寫么
MINA,Grizzly[grizzly-nio-framework],xSocket都是基於javanio的serverframework.這裡的性能缺陷的焦點是指當一條channel上的SelectionKey.OP_READready時,1.是由selectthread讀完數據之後再分發給應用程序的handler,2.還是直接就分發,由handlerthread來負責讀數據和handle.mina,xsocket是1.grizzly-nio-framework是2.儘管讀channelbuffer中bytes是很快的,但是如果我們放大,當連接channel達到上萬數量級,甚至,這種延遲響應的效果將會愈加明顯.MINA:forallselectedKeys{readdatathenfireMessageReceived.}xSocket:forallselectedKeys{readdata,appendittoreadQueuethenperformOnData.}其中mina在fireMessageReceived時沒有使用threadpool來分發,所以需要應用程序在handler.messageReceived中再分發.而xsocket的performOnData默認是分發給threadpool[WorkerPool],WorkerPool雖然解決了線程池中的線程不能充到最大的問題[跟tomcat6的做法一樣],但是它的調度機制依然缺乏靈活性.Grizzly:forallselectedKeys{[NIOContext—filterChain.execute—ourfilter.execute]bindInternal—startupAcceptor:啟動AbstractPollingIoAcceptor.Acceptor.run使用executor[Executor]的線程,註冊[interestOps:SelectionKey.OP_ACCEPT],然後wakeupselector.一旦有連接進來就構建NioSocketSession–對應–channal,然後session.getProcessor().add(session)將當前的channal加入到NioProcessor的selector中去[interestOps:SelectionKey.OP_READ],這樣每個連接中有請求過來就由相應的NioProcessor來處理.這裡有幾點要說明的是:1.一個NioSocketAcceptor對應了多個NioProcessor,比如NioSocketAcceptor就使用了SimpleIoProcessorPoolDEFAULT_SIZE=Runtime.getRuntime().availableProcessors()+1.當然這個size在newNioSocketAcceptor的時候可以設定.2.一個NioSocketAcceptor對應一個javanioselector[OP_ACCEPT],一個NioProcessor也對應一個javanioselector[OP_READ].3.一個NioSocketAcceptor對應一個內部的AbstractPollingIoAcceptor.Acceptor—thread.4.一個NioProcessor也對應一個內部的AbstractPollingIoProcessor.Processor—thread.5.在newNioSocketAcceptor的時候如果你不提供Executor(線程池)的話,那麼默認使用Executors.newCachedThreadPool().這個Executor將被NioSocketAcceptor和NioProcessor公用,也就是說上面的Acceptor—thread(一條)和Processor—thread(多條)都是源於這個Executor.當一個連接javaniochannal–NioSession被加到ProcessorPool[i]–NioProcessor中去後就轉入了AbstractPollingIoProcessor.Processor.run,AbstractPollingIoProcessor.Processor.run方法是運行在上面的Executor中的一條線程中的,當前的NioProcessor將處理註冊在它的selector上的所有連接的請求[interestOps:SelectionKey.OP_READ].AbstractPollingIoProcessor.Processor.run的主要執行流程:for(;;){intselected=selector(finalSELECT_TIMEOUT=1000L);.if(selected0){process();}}process()–forallsession-channal:OP_READ–read(session):這個read方法是AbstractPollingIoProcessor.privatevoidread(Tsession)方法.read(session)的主要執行流程是readchannal-datatobuf,ifreadBytes0thenIoFilterChain.fireMessageReceived(buf)/*我們的IoHandler.messageReceived將在其中被調用*/;到此minaNio處理請求的流程已經明了.mina處理請求的線程模型也出來了,性能問題也來了,那就是在AbstractPollingIoProcessor.Processor.run–process–read(persession)中,在process的時候mina是forallselected-channals逐次readdata再fireMessageReceived到我們的IoHandler.messageReceived中,而不是並發處理,這樣一來很明顯後來的請求將被延遲處理.我們假設:如果NioProcessorPool’ssize=2現在有200個客戶端同時連接過來,假設每個NioProcessor都註冊了100個連接,對於每個NioProcessor將依次順序處理這100個請求,那麼這其中的第100個請求要得到處理,那它只有等到前面的99個被處理完了.有人提出了改進方案,那就是在我們自己的IoHandler.messageReceived中利用線程池再進行分發dispatching,這個當然是個好主意.但是請求還是被延遲處理了,因為還有readdata所消耗的時間,這樣第100個請求它的數據要被讀,就要等前面的99個都被讀完才行,即便是增加ProcessorPool的尺寸也不能解決這個問題.此外mina的陷阱(這個詞較時髦)也出來了,就是在read(session)中,在說這個陷阱之前先說明一下,我們的client端向server端發送一個消息體的時候不一定是完整的只發送一次,可能分多次發送,特別是在client端忙或要發送的消息體的長度較長的時候.而mina在這種情況下就會call我們的IoHandler.messageReceived多次,結果就是消息體被分割了若干份,等於我們在IoHandler.messageReceived中每次處理的數據都是不完整的,這會導致數據丟失,無效.下面是read(session)的源碼:privatevoidread(Tsession){IoSessionConfigconfig=session.getConfig();IoBufferbuf=IoBuffer.allocate(config.getReadBufferSize());finalbooleanhasFragmentation=session.getTransportMetadata().hasFragmentation();try{intreadBytes=0;intret;try{if(hasFragmentation/*hasFragmentation一定為ture,也許mina的開發人員也意識到了傳輸數據的碎片問題,但是靠下面的處理是遠遠不夠的,因為client一旦間隔發送,ret就可能為0,退出while,不完整的readBytes將被fire*/){while((ret=read(session,buf))0){readBytes+=ret;if(!buf.hasRemaining()){break;}}}else{ret=read(session,buf);if(ret0){readBytes=ret;}}}finally{buf.flip();}if(readBytes0){IoFilterChainfilterChain=session.getFilterChain();filterChain.fireMessageReceived(buf);buf=null;if(hasFragmentation){if(readBytesIoAcceptor.accept()在port上阻塞,一旦有channel就從IoSocketDispatcherPool中獲取一個IoSocketDispatcher,同時構建一個IoSocketHandler和NonBlockingConnection,調用Server.LifeCycleHandler.onConnectionAccepted(ioHandler)initializetheIoSocketHandler.注意:IoSocketDispatcherPool.size默認為2,也就是說只有2條doselect的線程和相應的2個IoSocketDispatcher.這個和MINA的NioProcessor數是一樣的.說明2.IoSocketDispatcher[javanioSelector]:IoSocketHandler:NonBlockingConnection——1:1:1在IoSocketDispatcher[對應一個Selector].run中—IoSocketDispatcher.handleReadWriteKeys:forallselectedKeys{IoSocketHandler.onReadableEvent/onWriteableEvent.}IoSocketHandler.onReadableEvent的處理過程如下:1.readSocket();2.NonBlockingConnection.IoHandlerCallback.onDataNonBlockingConnection.onData—appendDataToReadBuffer:readQueueappenddata3.NonBlockingConnection.IoHandlerCallback.onPostDataNonBlockingConnection.onPostData—HandlerAdapter.onData[ourdataHandler]performOnDatainWorkerPool[threadpool].因為是把channel中的數據讀到readQueue中,應用程序的dataHandler.onData會被多次調用直到readQueue中的數據讀完為止.所以依然存在類似mina的陷阱.解決的方法依然類似,因為這裡有NonBlockingConnection.———————————————————————————————-再下面以grizzly-nio-frameworkv1.9.18源碼為例:tcpusagee.g:Controllersel=newController();sel.setProtocolChainInstanceHandler(newDefaultProtocolChainInstanceHandler(){publicProtocolChainpoll(){ProtocolChainprotocolChain=protocolChains.poll();if(protocolChain==null){protocolChain=newDefaultProtocolChain();//protocolChain.addFilter(ourapp’sfilter/*應用程序的處理從filter開始,類似mina.ioHandler,xSocket.dataHandler*/);//protocolChain.addFilter(newReadFilter());}returnprotocolChain;}});//如果你不增加自己的SelectorHandler,Controller就默認使用TCPSelectorHandlerport:18888sel.addSelectorHandler(ourapp’sselectorHandleronspecialport);sel.start();————————————————————————————————————說明1.Controller:ProtocolChain:Filter——1:1:n,Controller:SelectorHandler——1:n,SelectorHandler[對應一個Selector]:SelectorHandlerRunner——1:1,Controller.start()—forperSelectorHandlerstartSelectorHandlerRunnertorun.SelectorHandlerRunner.run()—selectorHandler.select()thenhandleSelectedKeys:forallselectedKeys{NIOContext.execute:dispatchingtothreadpoolforProtocolChain.execute—ourfilter.execute.}你會發現這裡沒有readdatafromchannel的動作,因為這將由你的filter來完成.所以自然沒有mina,xsocket它們的陷阱問題,分發提前了.但是你要注意SelectorHandler:Selector:SelectorHandlerRunner:Thread[SelectorHandlerRunner.run]都是1:1:1:1,也就是說只有一條線程在doSelectthenhandleSelectedKeys.相比之下雖然grizzly在並發性能上更優,但是在易用性方面卻不如mina,xsocket,比如類似mina,xsocket中表示當前連接或會話的IoSession,INonBlockingConnection對象在grizzly中由NIOContext來負責,但是NIOContext並沒有提供session/connectionlifecycleevent,以及常規的read/write操作,這些都需要你自己去擴展SelectorHandler和ProtocolFilter,從另一個方面也可以說明grizzly的可擴展性,靈活性更勝一籌.轉載
java Mina伺服器 java.io.IOException: Connection reset by peer,請問怎麼解決?
這個錯誤其實是可以忽略的,影響不到運行,有時候客戶端主動斷開鏈接就會報這個錯。你下面那個設置是線程池的設置跟這個沒有關係的
java mina 怎麼打成jar包放在伺服器上呀~~
jar包在伺服器上是不可運行的!
在伺服器上運行的是WEB程序是war包
jar包的安裝使用一般在手機上!
其次!jar包 是放在WEB程序下面的webroot下面的lib中的 只不過是給別人調用的!jar包 也可以做為插件 共別人使用!
因為要下班了!所以暫時這麼說吧!不知道LZ能接受不。。。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/257053.html