《電子技術應用》
您所在的位置:首頁 > 其他 > 設計應用 > Java非阻塞I/O在鄉村可視化遠程醫療系統中的應用
Java非阻塞I/O在鄉村可視化遠程醫療系統中的應用
來源:微型機與應用2011年第6期
顧和明
(長江師范學院 數學與計算機學院,重慶408100)
摘要: 分析了鄉村可視化遠程醫療系統采用多線程技術實現網絡通信存在的不足,闡述了Java非阻塞I/O的基本原理。系統采用非阻塞I/O通信技術只使用一個線程并行實現大量客戶無阻塞的通信,有效地減少了系統開銷,較好地提升了系統的性能。
Abstract:
Key words :

摘  要: 分析了鄉村可視化遠程醫療系統采用多線程技術實現網絡通信存在的不足,闡述了Java非阻塞I/O的基本原理。系統采用非阻塞I/O通信技術只使用一個線程并行實現大量客戶無阻塞的通信,有效地減少了系統開銷,較好地提升了系統的性能。
關鍵詞: 非阻塞I/O;遠程醫療系統;線程阻塞;通道

1 鄉村可視化遠程醫療系統的應用前景
    目前我國廣大的農村地區醫療條件比較差,這些地區的大量患者因為得不到及時有效的治療,給患者以及家屬帶來了不必要的痛苦。使用網絡多媒體通信技術實現的鄉村可視化遠程醫療系統可以讓高水平的醫療專家給鄉村的患者進行遠程診病,以及指導治療與護理。鄉村衛生所、鄉鎮醫院等醫療單位可以和具有優質醫療資源的醫院或直接與專家建立醫療合作關系,雙方合作使用可視化醫療系統,讓專家為病人進行遠程診療服務。在鄉村這一端,一般由專業醫務人員指導病人接受專家遠程診療,醫療專家通過可視化醫療系統實時對病人進行診斷、處方、治療甚至指導手術等。患者也可以在家中使用遠程醫療系統直接接受遠程專家的指導,尤其在處理突發性疾病時,可以在第一時間內得到醫療專家的幫助。目前隨著生活水平的大幅度提高,不少需要“私人醫生”的人員也可以方便地使用該系統得到醫療專家的服務。可見,可視化醫療系統有著很廣闊的應用市場和較好的發展前景。
2 鄉村可視化遠程醫療系統功能簡介
    鄉村遠程醫療系統可以同時提供若干對醫療服務,每一對服務有2個或2個以上的客戶端進行通信。客戶端分別由醫療專家和患者使用,醫療專家使用的客戶端稱為專家端,患者接受診療的客戶端稱為醫務端。每個客戶(醫務端和專家端)首先登錄服務器,服務器將每個登錄客戶的用戶名、IP地址等相關信息發送給相關的其他客戶,然后客戶端之間建立直接連接,并可進行文件傳送、文字和多媒體等通信。通過這種綜合的通信方式,醫療專家可以遠程為患者提供醫療服務。為了建立醫療檔案,服務器需要保存診療時間、參與人員、患者檢驗報告、病情診斷、處方等信息。患者還可以通過服務器進行專家預約,專家和患者均可以在服務器上進行診療信息查詢。由于視頻信息量比較大,且保存意義不是十分大,因此并不保存在服務器上。系統結構如圖1所示。

3 使用多線程和阻塞通信模式存在的局限
    可視化遠程醫療服務器需要同時為多個專家端和醫務端提供服務,在傳統的阻塞通信模式中使用多線程技術來處理多客戶連接,一般需要服務器為每個客戶端建立一個線程。但使用多線程技術存在以下局限:
    (1)Java虛擬機會為每個線程分配獨立的堆棧空間,工作線程數目越多,系統開銷就越大,而且增加了Java虛擬機調度線程的負擔,增加了線程之間同步的復雜性,提高了線程死鎖的可能性;
    (2)當主線程接收客戶連接,在醫療服務過程中,服務器從網絡發送或接收數據時,線程常常進入阻塞狀態,這就使工作線程的許多時間都浪費在阻塞操作上,CPU的利用率降低,此外Java虛擬機需要頻繁地轉讓CPU的使用權。
    由此可見,工作線程并不是越多越好。實驗表明,適量的工作線程會提高服務器的并發性能,但是當工作線程的數目達到某個極限而超出系統的負荷時,反而會降低并發性能,使得許多客戶端得不到服務器的及時響應。為了改善服務器性能,在遠程醫療系統中采用了Java非阻塞I/O通信技術。
4 Java非阻塞I/O工作原理簡介
    在傳統的阻塞通信模式中,服務器在接受客戶連接后創建Socket對象與客戶進行通信,Socket對象由線程進行管理。當有多個客戶連接時,就需要多個線程分別處理服務器與各個客戶的通信。Java非阻塞I/O通信服務器程序只需要一個線程就能夠實現多個客戶端的連接、同時接收多個客戶端發送的數據,以及同時向多個客戶端發送響應數據。這種非阻塞通信采用了基于Channel(通道)、Selector(選擇器) 、Buffer(緩沖器)的新模式。
    非阻塞I/O通信中Channel是一個接口,功能類似于傳統I/O中的Stream,但通道具有雙向性,既可讀入,也可寫出。SocketChannel和ServerSocketChannel均可實現Channel接口,它們是Socket和ServerSocket的替代類,但比Socket和ServerSocket具有更多的功能,它支持非阻塞通信、可選擇通信、異步通信和套接字對等通信等。
    由于網絡接收和傳送數據均比較緩慢,常常導致線程阻塞,影響系統性能。在Java非阻塞通信模式中使用Buffer來緩沖數據。SocketChannel和ServerSocketChannel對象一端連接著緩沖區,另一端連接著網絡。
    ServerSocketChannel和SocketChannel在Selector中注冊連接就緒事件、讀就緒事件和寫就緒事件。注冊時創建一個SelectionKey對象,這個SelectionKey對象用來跟蹤注冊事件的句柄,其中包含有注冊該對象的通道和緩沖區等信息。Selector會一直監控已經注冊的事件。當通道中有數據需要讀取時,Selector中就有已注冊的讀就緒事件發生,這時調用相關的程序可將通道中的數據讀到緩沖區中,然后再提供給程序進行處理。同樣地,當有數據需要通過網絡發送時,數據先進入緩沖區,這時Selector中就發生寫就緒事件,程序再利用通道向網絡發送數據[1]。
    非阻塞通信模式處理流程如下:
    while(檢測Selector對象,等待連接就緒事件、讀就緒事
件或寫就緒事件發生) {    //阻塞
        if(有客戶連接)//非阻塞
            接收客戶連接,創建SocketChannel對象與客
戶通信;
        if(某個SocketChannel輸入流中有可讀數據)
//非阻塞
            從輸入流讀數據;
        if(某個SocketChannel輸出流中有可寫數據)
//非阻塞
            向輸出流寫數據;
    }
    上述處理流程采用輪詢工作方式,當某一種操作就緒時,執行該操作,否則就查看是否還有其他就緒操作可以執行,線程不會因為某一個連接、讀、寫等操作還沒有就緒,就進入阻塞狀態。在非阻塞通信模式中,只需要一個線程管理Selector對象就可以了,而不需要多線程。并且只有檢測Selector對象時才有可能導致線程阻塞,因此可以大大提高系統的性能。
5 非阻塞通信在鄉村可視化遠程醫療系統中的應用研究
    在鄉村可視化遠程醫療系統中,服務器端需要和各個客戶端建立連接、接受客戶端的操作請求并將操作結果返回給客戶端。服務器只需要使用一個線程就可以處理客戶端連接請求和向各個客戶端讀寫數據,服務器自身進行的數據庫操作可以使用另外的線程。
    專家端和醫務端在服務器端的數據庫中進行查詢、插入和修改等操作,這些操作信息是各種SQL語句,服務器返回給專家端和醫務端的是查詢、保存或修改結果,它們可能是一個字符串、一條記錄,也可能是多條記錄。為了方便操作,這些信息均封裝成XML格式,根標志為<teleMedi></teleMedi>。這種格式封裝數據便于檢驗數據的完整性與正確性,也容易解析。在非阻塞通信中,除boolean類型以外,每種基本數據類型都有對應的緩沖區類,在本系統中使用ByteBuffer類對象數據緩沖區。程序中需要向網絡發送數據時,數據進入緩沖區前先要把字符數據編碼成字節數據,然后再由通道向網絡發送,而從網絡上接收的字節流數據先存放進緩沖區,解碼后再由程序處理。
    在非阻塞通信模式中,一次完整的數據發送可能需要多次讀緩沖區,這避免了阻塞通信模式中讀取數據時間拖得過長而導致的線程阻塞。每次讀緩沖區后都要進行數據完整性檢查,由于采用XML格式封裝數據,所以很容易檢驗是不是讀取到了完整的數據。
    鄉村可視化遠程醫療系統中每次通過網絡讀寫的數據長短不同。醫療中需要傳送的數據最常見的長度小于1 KB,因此緩沖區最初設定為1 KB,當數據超過這個長度時,將緩沖區的容量擴大一倍,如果超過2 KB,再將緩沖區擴大一倍,如此類推。使用這種可伸縮的方式可以更有效地利用內存資源。
6 非阻塞通信在鄉村可視化遠程醫療系統中的實現[2]
    在非阻塞模式下,服務器主程序MedicalSever只使用一個線程,使用Selector監控接收連接就緒事件、讀就緒事件和寫就緒事件。限于篇幅,本文僅介紹幾段主要的代碼。
    (1)MedicalServer類的構造方法負責啟動服務器,把它綁定到一個本地端口,主要代碼如下:
    selector=Selector.open();//創建一個Selector對象
    ssChannel=ServerSocketChannel.open();
//創建ServerSocketChannel對象
    ssChannel.configureBlocking(false);
//設置ServerSocketChannel為阻塞工作模式
    ssChannel.socket().bind(new InetSocketAddress(port));
//綁定到本地端口
    (2)MedicalSever類的serve()方法負責輪詢Selector,主要代碼如下:
    public void serve() throws IOException{
        ssChannel.register(selector,SelectorKey.OP_ACCEPT);
//在Selector中注冊連接就緒事件
        while(selector.select()>0){
            Set readyKeys=selector.selectedKeys();
//獲取Selector中就緒事件集合
            Iterator it=readyKeys.iterator();
            while(it.hasNext()){
            SelectorKey key=null;
            try{
                key=(SelectionKey)it.next();
//獲取某個就緒事件
                it.remove();//獲取就緒事件后刪除
                if(key.isReadable()){處理連接就緒事件}
                if(key.isReadable()){處理讀就緒事件}
                if(key.isWritable()){處理寫就緒事件}
            }catch(IOException e){   }}}
    (3)處理連接就緒事件方法中的主要代碼如下:
    ServerSocketChannel ssc=(ServerSocketChannel)key.channel();
    SocketChannel sChannel=(SocketChannel)ssc.accept();
//獲取關系的SocketChannel
    socketChannel.configureBlocking(false);
//將SocketChannel設置為非阻塞模式
    ByteBuffer buffer=ByteBuffer.allocate(1024);//分配緩沖區
    socketChannel.register(selector,SelectorKey.OP_READ|
SelectionKey.OP_WRITER,buffer);
//注冊讀就緒和寫就緒事件
    (4)處理讀就緒事件方法中的主要代碼如下:
    public void receive(SelectionKey key)throws IOException{
        ByteBuffer sBuffer=(ByteBuffer)key.attachment();
//獲取與SelectorKey綁定的緩沖區
        SocketChannel sChannel=
(SocketChannel)key.channel();//獲得通道
        ByteBuffer buff=ByteBuffer.allocate(1024)
//創建輔助緩沖區
        sChannel.read(buff);//從通道中讀數據暫存到buff中
        sBuffer.put(buff); }//把buff中的內容拷貝到緩沖區
    在非阻塞模式下,sChannel.read(buff)方法無法保證一次把全部數據都讀完,因此只好把每次讀到的數據先存放到buff中,并判斷每次讀到的數據是否以</teleMedi>結尾,當數據讀取完整了,再復制到sBuffer中提交給程序。
    (5)處理寫就緒事件方法中的主要代碼如下:
    public void send(SelectionKey key)throws IOExceptio{
        ByteBuffer sBuffer=(ByteBuffer)key.attachment();
//獲取需要發送數據的緩沖區
        SocketChannel sChannel=(SocketChannel)key.channel();
        synchronized(sBuffer)
        {        sBuffer.flip();//將緩沖當前的位置值設為
極限,將位置設為0,為下一步復制數據做準備
            sChannel.write(sBuffer);//發送緩沖區中的數據
            sChannel.compact();}//刪除已發送的數據
    (6)當每個緩沖區容量不夠時,需要擴大緩沖區,主要代碼如下:
    protected void resizeBuffer(ByteBuffer bb)
    {  if(bb.remaining()<10){//判斷剩余容量是否
小于10 B
     ByteBuffer bBuffer=ByteBuffer.allocate(bb.capacity()*2);
//容量擴大一倍
     bb.flip();
     bBuffer.put(bb);//把原緩沖區中數據復制到
新緩沖區中
     bb=bBuffer;}}
    鄉村可視化遠程醫療系統中使用Java非阻塞I/O通信技術,可以只使用一個主線程就能實現網絡連接、讀和寫操作,避免了多線程中讀或寫引起的線程阻塞,大幅降低了服務器應用程序的開銷,有效地提高了系統的性能。
參考文獻
[1] 吳易,王凌.Java技術在P2P環境下的應用[J].微計算機信息,2005(3):154-155.
[2] JavaTM Platform Standard Edition 6 API Specification[S]. http://download.oracle.com/javase/6/docs/api/.

此內容為AET網站原創,未經授權禁止轉載。
主站蜘蛛池模板: 亚洲免费小视频 | 一级片免费在线观看 | 一级毛片 在线播放 | 国产在线视频www色 国产在线视频国产永久视频 | 亚洲成人手机在线 | 亚洲国产高清在线精品一区 | 成人亚洲欧美日韩中文字幕 | 亚洲成人免费观看 | 国产亚洲人成网站天堂岛 | 亚洲经典激情春色另类 | 欧美一区二区三区成人看不卡 | 天天综合天天做 | 毛片在线观看网站 | 亚洲三级视频在线 | 欧美大胆性生话 | 亚洲一区二区三区影院 | 免费黄色网址网站 | www永久免费视频 | 美女福利视频导航 | 亚洲最新中文字幕 | 日日操综合| 无遮羞无删减肉动漫在线观看 | 又黄又爽的视频免费看 | 99久久中文字幕伊人情人 | 视频在线18羞羞 | 欧美激情精品久久久久久不卡 | 一级片中文字幕 | 午夜宅男影院 | 天天做天天爱夜夜想毛片 | 欧美黄色免费大片 | 97免费在线观看 | 天天干天天色天天射 | 日韩v片| 在线观看中文字幕亚洲 | 欧美国产亚洲精品a第一页 欧美国产在线观看 | 91欧美在线视频 | 国产精品一区二区手机看片 | 男人女人的免费视频网站 | 亚洲欧美卡通另类 | 26uuu另类亚洲欧美日本一 | 噜噜噜狠狠夜夜躁精品 |