《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 其他 > 設(shè)計(jì)應(yīng)用 > Java非阻塞I/O在鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)中的應(yīng)用
Java非阻塞I/O在鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)中的應(yīng)用
來(lái)源:微型機(jī)與應(yīng)用2011年第6期
顧和明
(長(zhǎng)江師范學(xué)院 數(shù)學(xué)與計(jì)算機(jī)學(xué)院,,重慶408100)
摘要: 分析了鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)采用多線(xiàn)程技術(shù)實(shí)現(xiàn)網(wǎng)絡(luò)通信存在的不足,闡述了Java非阻塞I/O的基本原理,。系統(tǒng)采用非阻塞I/O通信技術(shù)只使用一個(gè)線(xiàn)程并行實(shí)現(xiàn)大量客戶(hù)無(wú)阻塞的通信,,有效地減少了系統(tǒng)開(kāi)銷(xiāo),較好地提升了系統(tǒng)的性能,。
Abstract:
Key words :

摘  要: 分析了鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)采用多線(xiàn)程技術(shù)實(shí)現(xiàn)網(wǎng)絡(luò)通信存在的不足,,闡述了Java非阻塞I/O的基本原理。系統(tǒng)采用非阻塞I/O通信技術(shù)只使用一個(gè)線(xiàn)程并行實(shí)現(xiàn)大量客戶(hù)無(wú)阻塞的通信,,有效地減少了系統(tǒng)開(kāi)銷(xiāo),,較好地提升了系統(tǒng)的性能。
關(guān)鍵詞: 非阻塞I/O,;遠(yuǎn)程醫(yī)療系統(tǒng),;線(xiàn)程阻塞;通道

1 鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)的應(yīng)用前景
    目前我國(guó)廣大的農(nóng)村地區(qū)醫(yī)療條件比較差,,這些地區(qū)的大量患者因?yàn)榈貌坏郊皶r(shí)有效的治療,,給患者以及家屬帶來(lái)了不必要的痛苦。使用網(wǎng)絡(luò)多媒體通信技術(shù)實(shí)現(xiàn)的鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)可以讓高水平的醫(yī)療專(zhuān)家給鄉(xiāng)村的患者進(jìn)行遠(yuǎn)程診病,,以及指導(dǎo)治療與護(hù)理,。鄉(xiāng)村衛(wèi)生所、鄉(xiāng)鎮(zhèn)醫(yī)院等醫(yī)療單位可以和具有優(yōu)質(zhì)醫(yī)療資源的醫(yī)院或直接與專(zhuān)家建立醫(yī)療合作關(guān)系,,雙方合作使用可視化醫(yī)療系統(tǒng),,讓專(zhuān)家為病人進(jìn)行遠(yuǎn)程診療服務(wù)。在鄉(xiāng)村這一端,,一般由專(zhuān)業(yè)醫(yī)務(wù)人員指導(dǎo)病人接受專(zhuān)家遠(yuǎn)程診療,,醫(yī)療專(zhuān)家通過(guò)可視化醫(yī)療系統(tǒng)實(shí)時(shí)對(duì)病人進(jìn)行診斷,、處方、治療甚至指導(dǎo)手術(shù)等,?;颊咭部梢栽诩抑惺褂眠h(yuǎn)程醫(yī)療系統(tǒng)直接接受遠(yuǎn)程專(zhuān)家的指導(dǎo),尤其在處理突發(fā)性疾病時(shí),,可以在第一時(shí)間內(nèi)得到醫(yī)療專(zhuān)家的幫助,。目前隨著生活水平的大幅度提高,不少需要“私人醫(yī)生”的人員也可以方便地使用該系統(tǒng)得到醫(yī)療專(zhuān)家的服務(wù),??梢?jiàn),可視化醫(yī)療系統(tǒng)有著很廣闊的應(yīng)用市場(chǎng)和較好的發(fā)展前景,。
2 鄉(xiāng)村可視化遠(yuǎn)程醫(yī)療系統(tǒng)功能簡(jiǎn)介
    鄉(xiāng)村遠(yuǎn)程醫(yī)療系統(tǒng)可以同時(shí)提供若干對(duì)醫(yī)療服務(wù),,每一對(duì)服務(wù)有2個(gè)或2個(gè)以上的客戶(hù)端進(jìn)行通信??蛻?hù)端分別由醫(yī)療專(zhuān)家和患者使用,,醫(yī)療專(zhuān)家使用的客戶(hù)端稱(chēng)為專(zhuān)家端,患者接受診療的客戶(hù)端稱(chēng)為醫(yī)務(wù)端,。每個(gè)客戶(hù)(醫(yī)務(wù)端和專(zhuān)家端)首先登錄服務(wù)器,,服務(wù)器將每個(gè)登錄客戶(hù)的用戶(hù)名、IP地址等相關(guān)信息發(fā)送給相關(guān)的其他客戶(hù),,然后客戶(hù)端之間建立直接連接,,并可進(jìn)行文件傳送、文字和多媒體等通信,。通過(guò)這種綜合的通信方式,,醫(yī)療專(zhuān)家可以遠(yuǎn)程為患者提供醫(yī)療服務(wù)。為了建立醫(yī)療檔案,,服務(wù)器需要保存診療時(shí)間,、參與人員、患者檢驗(yàn)報(bào)告,、病情診斷,、處方等信息?;颊哌€可以通過(guò)服務(wù)器進(jìn)行專(zhuān)家預(yù)約,,專(zhuān)家和患者均可以在服務(wù)器上進(jìn)行診療信息查詢(xún)。由于視頻信息量比較大,,且保存意義不是十分大,,因此并不保存在服務(wù)器上。系統(tǒng)結(jié)構(gòu)如圖1所示。

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

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載,。