月亮的太陽

          小乖的BLOG
          posts - 114, comments - 41, trackbacks - 0, articles - 27
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

          怎樣用Java實現(xiàn)MSN Messager的功能

          Posted on 2005-12-11 16:05 月亮的太陽 閱讀(481) 評論(0)  編輯  收藏 所屬分類: 編程
          現(xiàn)在的即時通訊軟件琳瑯滿目,大家耳熟能詳?shù)臒o非就是騰訊公司的QQ,微軟公司的MSN Messenger以及網(wǎng)易的泡泡,就用戶量而言這三者應該是名列前茅的。但是騰訊公司的QQ以及網(wǎng)易的泡泡由于并沒有公開其客戶端與服務器之間的通訊協(xié)議導致開發(fā)者很難利用起這一龐大的用戶群體來開辟另外的服務渠道。

          MSN Messenger這一由世界頭號軟件商-微軟公司開發(fā)的即時通訊軟件,憑借其與windows操作系統(tǒng)和整個微軟產(chǎn)品家族的緊密結合,簡單實用、性能穩(wěn)定、世界通用等特點,很快被中國用戶接受,目前其用戶正在以幾何數(shù)字增長。但是讓開發(fā)者雀躍的是該軟件同時也提供了開放的API以及開放的通訊協(xié)議。

          著名的MSN Plus就是一款利用其API開發(fā)的用于擴展MSN Messenger功能的插件。而我們今天要介紹的jMSN則是封裝了MSN Messenger開放的通訊協(xié)議的Java API,通過這個API開發(fā)者完全可以使用Java語言模擬出MSN Messenger軟件,API的作者也提供一個用Java語言編寫的在某方面功能甚至比MSN Messenger還強大的MSN 客戶端軟件。由于采用了跨平臺的Java語言開發(fā),因此該軟件也可同時運行于其他操作系統(tǒng),目前已經(jīng)經(jīng)過測試的有各種Linux系統(tǒng)以及Mac OS上,當然還有視窗操作系統(tǒng)。

          jMSN是一個韓國人開發(fā)的開放源碼的API,可以從http://sourceforge.net/projects/jmsn/站點上下載,該項目的首頁基本上以韓文為主,包括它的API文檔的說明都是韓文。這個讓我非常頭疼,不過沒有關系,因為jMSN非常簡單,如果沒有什么特殊情況下不看那些說明也沒有關系。

          jmsn是一個完整的Java應用程序,下載解壓后可以直接運行,運行的界面跟微軟的MSN Messenger很類似,包括操作上都非常一致,如果你的操作系統(tǒng)是Linux或者其他那都可以直接用它來替代微軟的程序。另外一個是msnm-lib,這個就是我們今天要介紹的API,它僅僅是一個開發(fā)包,在jmsn組件中已經(jīng)包含了這個包。

          你可能想先體驗一下jmsn自帶的程序看看到底能完成什么樣的功能吧?解壓jmsn壓縮包后的目錄中會有一個可執(zhí)行文件,不過如果你的JDK不是使用安裝程序安裝的,建議你不用執(zhí)行它,它會找不到jre的。你可以使用命令行來啟動這個程序,這樣做有個好處是你還可以看到運行中打印出來的信息。

          應該說界面跟MSN Messenger是非常類似的。用戶可以通過它發(fā)送和接收消息等。在啟動jMSN的命令行窗口中可以看到jMSN與服務器之間通訊的詳細信息。

          前面我們主要在介紹jMSN大概的情況,介紹它能完成什么樣的功能。下面我們開始來了解怎么利用jMSN自帶的API:msnm-lib來實現(xiàn)這些功能。我們可以通過msnm-lib來完成與MSN服務器之間的通訊而不需要我們?nèi)ゲ傩木唧w的通訊協(xié)議的細節(jié)。

          事實上msnm-lib給我們做了更多的事情使得我們使用msnm-lib來開發(fā)一個MSN應用程序變得非常的簡單,這也就是我前面提到的我們完全可以不去可能它所提供的韓文API文檔的緣故,因為使用它實在是太簡單了。

          閑話說了那么多,現(xiàn)在我們就開始來開發(fā)我們自己基于Java的跨平臺的MSN客戶端程序。相信聽到這句大家都會覺得血脈膨脹,沒錯,還有什么比動手寫程序更讓人興奮的事情呢?何況還是基于Java的、跨平臺的!

          我們先給出一段可運行的代碼來完成一個最簡單的功能:當有人把它加入好友時,程序自動將之加入好友,當有人給它發(fā)送信息,程序自動回復一條相同的信息。完成這么簡單的功能的代碼如下:

          /* 
          * Created on 2003-11-21 by Liudong 
          */ 
          package jmsn.demo; 
          
          import rath.msnm.MSNMessenger; 
          import rath.msnm.SwitchboardSession; 
          import rath.msnm.UserStatus; 
          import rath.msnm.entity.MsnFriend; 
          import rath.msnm.event.MsnAdapter; 
          import rath.msnm.msg.MimeMessage; 
          /** 
          * MSN演示程序 
          * @author Liudong 
          */ 
          public class MSNDaemon extends Thread
          { 
          private static MSNMessenger msn; 
          
          public static void main(String[] args) 
          { 
          msn = new MSNMessenger
          ("youraccount@hotmail.com", "password"); 
          msn.setInitialStatus(UserStatus.ONLINE); 
          msn.addMsnListener(new MSNAdapter(msn)); 
          msn.login(); 
          System.out.println
          ("Waiting for the response...."); 
          //捕捉Ctrl+C的輸入以便注銷MSN的登錄 
          Runtime.getRuntime().
          addShutdownHook(new MSNDaemon()); 
          } 
          /** 
          * 用戶中止程序執(zhí)行 
          */ 
          public void run() 
          { 
          msn.logout(); 
          System.out.println("MSN Logout OK"); 
          } 
          } 
          /** 
          * MSN消息事件處理類 
          * @author Liudong 
          */ 
          class MSNAdapter extends MsnAdapter
          { 
          
          MSNMessenger messenger; 
          
          public MSNAdapter(MSNMessenger messenger)
          { 
          this.messenger = messenger; 
          } 
          /** 
          * 某人正在輸入信息 
          */ 
          public void progressTyping( 
          SwitchboardSession ss, 
          MsnFriend friend, 
          String typingUser)
          { 
          System.out.println
          (friend.getLoginName() + "正在輸入信息..."); 
          } 
          /** 
          * 收到消息的時候執(zhí)行該方法 
          */ 
          public void instantMessageReceived( 
          SwitchboardSession ss, 
          MsnFriend friend, 
          MimeMessage mime) 
          { 
          System.out.print("接收到消息:
          " + friend.getFriendlyName() + "->"); 
          System.out.println(mime.getMessage()); 
          try { 
          //發(fā)送相同的回復信息給發(fā)送者 
          messenger.sendMessage
          (friend.getLoginName(), mime); 
          } catch (Exception e)
          { 
          e.printStackTrace(); 
          } 
          } 
          /** 
          * 登錄成功后執(zhí)行該方法 
          */ 
          public void loginComplete(MsnFriend own)
          { 
          System.out.println
          (own.getLoginName() + " Login OK"); 
          } 
          /** 
          * 登錄失敗后執(zhí)行該方法 
          */ 
          public void loginError(String header)
          { 
          System.out.println
          ("Login Failed: " + header); 
          } 
          /** 
          * 好友離線時執(zhí)行該方法 
          */ 
          public void userOffline(String loginName)
          { 
          System.out.println
          ("USER " + loginName + " Logout."); 
          } 
          /** 
          * 好友上線時執(zhí)行該方法 
          */ 
          public void userOnline(MsnFriend friend)
          { 
          System.out.println
          ("USER "+friend.getFriendlyName()+" Login."); 
          } 
          /** 
          * 有人加我為好友時執(zhí)行 
          */ 
          public void whoAddedMe(MsnFriend friend)
          { 
          System.out.println
          ("USER " + friend.getLoginName() + " Addme."); 
          try { 
          messenger.addFriend(friend.getLoginName()); 
          } catch (Exception e)
          { 
          e.printStackTrace(); 
          } 
          } 
          /** 
          * 有人把我從好友列表中刪除時執(zhí)行 
          */ 
          public void whoRemovedMe(MsnFriend friend)
          { 
          System.out.println
          ("USER "+friend.getLoginName()+" Remove me."); 
          try { 
          messenger.removeFriend(friend.getLoginName()); 
          } catch (Exception e) 
          { 
          e.printStackTrace(); 
          } 
          } 
          }


          除了兩個常用的對象MsnFriend以及MimeMessage分別用來表示我的好友以及MSN信息外,其他我們需要了解的也就是MSNMessenger以及MsnAdapter了。當然了前提是我們不需要除了聊天外的其他功能,例如文件傳輸?shù)鹊取?

          類MSNMessenger對應著一個帳號的一次登錄會話。我們僅僅是需要告訴MSNMessenger類我們登錄所用的帳號、密碼、登錄后的初始狀態(tài)以及我們怎么來處理從MSN服務器上接收到的任何信息。

          在msnm-lib中,處理MSN信息是通過一個叫MsnAdapter類來處理的,這個類定義了如何處理例如收到消息、有人加我為好友等等的事件,開發(fā)者可以重載這些方法以便進行自行處理。

          我們自行擴展MsnAdapter的類必須告訴MSNMessenger實例知道,這也就是我們前面代碼中的

          msn.addMsnListener(new MSNAdapter(msn));


          自行擴展MsnAdapter的類是用來處理被動消息的,例如有人給我發(fā)消息等。當我們要發(fā)送消息給別人的時候就需要用到MSNMessenger的實例,這也就是我們?yōu)槭裁匆袽SNMessenger的實例傳遞給MSNAdapter的原因,因為當我們接收到任何消息時要給發(fā)送人回復一條相同的信息。到此我們前面提出的簡單功能已經(jīng)完成了,讀者可以在自己的機器上進行測試,運行時需要用到msnm-lib庫,也就是msnm.jar文件。

          關于多人聊天:

          MSN有另外一個不錯的功能就是多人同時聊天,msnm-lib對這個功能支持也非常好。在MsnAdapter中定義的方法instantMessageReceived的第一個參數(shù)類型為SwitchboardSession。當接收到消息時,我們可以從這個參數(shù)中獲取多人聊天的一個會話標識,同時可以通過getMsnFriends來讀取參與當前聊天的所有好友。當你要主動發(fā)送消息的時候你就必須從SwitchboardSession中讀取所有的好友并給他們一一發(fā)送信息。

          關于文件傳輸:

          可能這是我發(fā)現(xiàn)的關于msnm-lib的唯一不足,或者說還不夠完善的部分。經(jīng)過測試發(fā)現(xiàn)使用微軟的MSN程序可以正常傳輸文件的兩臺機器用jMSN卻無法傳輸,錯誤信息都是說連接超時,這兩臺機器不在同一個子網(wǎng)。

          相信msnm-lib對這個功能并沒有進行處理。由于并沒有兩臺直接連接Internet的機器,因此關于jMSN的文件傳輸一直都沒有辦法來做一個試驗,希望新版本的msnm-lib能解決好這個問題。
          海邊的貝殼
          主站蜘蛛池模板: 长乐市| 鹤庆县| 阿坝| 大田县| 调兵山市| 图木舒克市| 兴海县| 河北区| 咸丰县| 确山县| 华坪县| 紫云| 岢岚县| 报价| 富锦市| 克什克腾旗| 郸城县| 珲春市| 铜山县| 台东市| 越西县| 北票市| 嘉义市| 莱芜市| 城步| 甘谷县| 濮阳市| 汉中市| 滕州市| 扶绥县| 瑞安市| 神农架林区| 西乌珠穆沁旗| 曲水县| 柳河县| 海门市| 建始县| 谷城县| 衡山县| 普宁市| 来宾市|