贝高林的Blog

IMS——更软的软交换,固移融合——IMS解决方案

用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
lin_bei的公告
<EMBED src="http://www.aswis.net/100000/clock/clock6.swf" type="application/x-shockwave-flash" width="180" height="180"></EMBED> <body style="CURSOR:url(http://img.xiaonei.com/photos/81/941/orig15467.ani)"></body> <!-- 中国农历开始 --> <SCRIPT language=JavaScript><!-- var lunarInfo=new Array( 0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2, 0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977, 0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970, 0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950, 0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557, 0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,0x0e950,0x06aa0, 0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0, 0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b5a0,0x195a6, 0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570, 0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0, 0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5, 0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930, 0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530, 0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45, 0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0) var Animals=new Array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"); var Gan=new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸"); var Zhi=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"); var now = new Date(); var SY = now.getYear(); var SM = now.getMonth(); var SD = now.getDate(); //==== 传入 offset 传回干支, 0=甲子 function cyclical(num) { return(Gan[num%10]+Zhi[num%12])} //==== 传回农历 y年的总天数 function lYearDays(y) { var i, sum = 348 for(i=0x8000; i>0x8; i>>=1) sum += (lunarInfo[y-1900] & i)? 1: 0 return(sum+leapDays(y)) } //==== 传回农历 y年闰月的天数 function leapDays(y) { if(leapMonth(y)) return((lunarInfo[y-1900] & 0x10000)? 30: 29) else return(0) } //==== 传回农历 y年闰哪个月 1-12 , 没闰传回 0 function leapMonth(y) { return(lunarInfo[y-1900] & 0xf)} //====================================== 传回农历 y年m月的总天数 function monthDays(y,m) { return( (lunarInfo[y-1900] & (0x10000>>m))? 30: 29 )} //==== 算出农历, 传入日期物件, 传回农历日期物件 // 该物件属性有 .year .month .day .isLeap .yearCyl .dayCyl .monCyl function Lunar(objDate) { var i, leap=0, temp=0 var baseDate = new Date(1900,0,31) var offset = (objDate - baseDate)/86400000 this.dayCyl = offset + 40 this.monCyl = 14 for(i=1900; i<2050 && offset>0; i++) { temp = lYearDays(i) offset -= temp this.monCyl += 12 } if(offset<0) { offset += temp; i--; this.monCyl -= 12 } this.year = i this.yearCyl = i-1864 leap = leapMonth(i) //闰哪个月 this.isLeap = false for(i=1; i<13 && offset>0; i++) { //闰月 if(leap>0 && i==(leap+1) && this.isLeap==false) { --i; this.isLeap = true; temp = leapDays(this.year); } else { temp = monthDays(this.year, i); } //解除闰月 if(this.isLeap==true && i==(leap+1)) this.isLeap = false offset -= temp if(this.isLeap == false) this.monCyl ++ } if(offset==0 && leap>0 && i==leap+1) if(this.isLeap) { this.isLeap = false; } else { this.isLeap = true; --i; --this.monCyl;} if(offset<0){ offset += temp; --i; --this.monCyl; } this.month = i this.day = offset + 1 } function YYMMDD(){ var cl = '<font color="#0000df" STYLE="font-size:9pt;">'; if (now.getDay() == 0) cl = '<font color="#c00000" STYLE="font-size:9pt;">'; if (now.getDay() == 6) cl = '<font color="#00c000" STYLE="font-size:9pt;">'; return(cl+SY+'年'+(SM+1)+'月'+SD+'日</font>'); } function weekday(){ var day = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六"); var cl = '<font color="#ff0000" STYLE="font-size:9pt;">'; if (now.getDay() == 0) cl = '<font color="#c00000" STYLE="font-size:9pt;">'; if (now.getDay() == 6) cl = '<font color="#00c000" STYLE="font-size:9pt;">'; return(cl+ day[now.getDay()]+ '</font>'); } //==== 中文日期 function cDay(m,d){ var nStr1 = new Array('日','一','二','三','四','五','六','七','八','九','十'); var nStr2 = new Array('初','十','廿','卅',' '); var s; if (m>10){s = '十'+nStr1[m-10]} else {s = nStr1[m]} s += '月' switch (d) { case 10:s += '初十'; break; case 20:s += '二十'; break; case 30:s += '三十'; break; default:s += nStr2[Math.floor(d/10)]; s += nStr1[d%10]; } return(s); } function solarDay1(){ var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var cl = '<font color="violet" STYLE="font-size:9pt;">'; var tt = '【'+Animals[(SY-4)%12]+'】'+cyclical(lDObj.monCyl)+'月 '+cyclical(lDObj.dayCyl++)+'日' ; return(cl+tt+'</font>'); } function solarDay2(){ var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var cl = '<font color="#000066" STYLE="font-size:9pt;">'; //农历BB'+(cld[d].isLeap?'闰 ':' ')+cld[d].lMonth+' 月 '+cld[d].lDay+' 日 var tt = cyclical(SY-1900+36)+'年 '+cDay(lDObj.month,lDObj.day); return(cl+tt+'</font>'); } function solarDay3(){ var sTermInfo = new Array(0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758) var solarTerm = new Array("小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至") var lFtv = new Array("0101*春节","0109 老婆生日","0115 元宵节","0505 端午节","0707 七夕情人节","0715 中元节","0815 中秋节","0909 重阳节","1208 腊八节","1224 小年","0100*除夕") var sFtv = new Array("0101*元旦","0214 情人节","0308 妇女节","0312 植树节","0315 消费者权益日","0401 愚人节","0501 劳动节","0504 青年节","0512 护士节","0601 儿童节","0701 建党节 香港回归纪念", "0801 建军节","0808 父亲节","0909 毛泽东逝世纪念","0910 教师节","0928 孔子诞辰","1001*国庆节", "1006 老人节","1024 联合国日","1112 孙中山诞辰","1220 澳门回归纪念","1225 圣诞节","1226 毛泽东诞辰") var sDObj = new Date(SY,SM,SD); var lDObj = new Lunar(sDObj); var lDPOS = new Array(3) var festival='',solarTerms='',solarFestival='',lunarFestival='',tmp1,tmp2; //农历节日 for(var i = 0 ; i < lFtv.length ; i ++) if(lFtv[i].match(/^(\d{2})(.{2})([\s\*])(.+)$/)) { tmp1=Number(RegExp.$1)-lDObj.month tmp2=Number(RegExp.$2)-lDObj.day if(tmp1==0 && tmp2==0) lunarFestival=RegExp.$4 } //国历节日 for(var i = 0 ; i < sFtv.length ; i ++) if(sFtv[i].match(/^(\d{2})(\d{2})([\s\*])(.+)$/)){ tmp1=Number(RegExp.$1)-(SM+1) tmp2=Number(RegExp.$2)-SD if(tmp1==0 && tmp2==0) solarFestival = RegExp.$4 } //节气 tmp1 = new Date((31556925974.7*(SY-1900)+sTermInfo[SM*2+1]*60000)+Date.UTC(1900,0,6,2,5)) tmp2 = tmp1.getUTCDate() if (tmp2==SD) solarTerms = solarTerm[SM*2+1] tmp1 = new Date((31556925974.7*(SY-1900)+sTermInfo[SM*2]*60000)+Date.UTC(1900,0,6,2,5)) tmp2= tmp1.getUTCDate() if (tmp2==SD) solarTerms = solarTerm[SM*2] if(solarTerms == '' && solarFestival == '' && lunarFestival == '') festival = ''; else festival = '<TABLE WIDTH=100% BORDER=0 CELLPADDING=2 CELLSPACING=0 BGCOLOR="#CCFFCC"><TR><TD>'+ '<FONT COLOR="#000000" STYLE="font-size:9pt;">'+solarTerms + ' ' + solarFestival + ' ' + lunarFestival+'</FONT></TD>'+ '</TR></TABLE>'; var cl = '<font color="#000066" STYLE="font-size:9pt;">'; return(cl+festival+'</font>'); } function setCalendar(){ document.write('<table align=center CELLPADDING=2 CELLSPACING=0 border=1><tr><td bgcolor=#FEFEEF><table border=0 CELLPADDING=0 CELLSPACING=0><tr><td align=center>'); document.write(YYMMDD()+'&nbsp;&nbsp;'+weekday()); document.write('</td></tr>'); document.write('<tr><td align=center>'); document.write(solarDay1()); document.write('</td></tr><tr><td align=center>'); document.write(solarDay2()); document.write('</td></tr><tr><td>'); document.write(solarDay3()); document.write('</td></tr></table></td></tr></table>'); } setCalendar(); //--></SCRIPT> <!-- 中国农历结束 --> <!-- 新闻滚动 --> <iframe name=sina_roll src=http://news.sina.com.cn/o/allnews/input/index.html height=14 width=175 Frameborder=No Border=0 Marginwidth=0 Marginheight=0 Scrolling=No></iframe> <!-- 新闻滚动结束--> <br> <a href=http://blog.csdn.net/lin_bei title="点击此处进入首页">首页</a> <!-- QQ在线状态显示 --> <a href="http://wpa.qq.com/msgrd?V=1&Uin=94799058"><img border=0 src="http://wpa.qq.com/pa?p=1:94799058:7" alt="点击这里给我发消息"></a><!-- Begin Online Status Indicator code --><!-- End Online Status Indicator code --> <script language="JavaScript" type="text/javascript" charset="gb2312" src=" http://c6.50bang.com/click.js?user_id=403116"></script> <br> <embed src="http://www.yyzjzx.net/jswy/mhf/cailiao/endless%20love.mp3" width="170" height="25" type="audio/mpeg" autostart="true" loop="infinite"></embed> <img src=http://nmc2.jy.js.cn/cgi-bin/counter.pl?id=csdn_blog_lin&md=a4&ln=6&from=0&bd=$0;$0;$255> <!-- Google--> <script>var s="http://www.google.com/search?hl=zh-CN&lr=lang_zh-CN&q=";</script> <a href="http://www.google.com"><img border="0" src="http://www.google.com/logos/Logo_25wht.gif"></a><input name="q" type="text" value="" style="font-size:9pt"> <input name="btnG" type="button" value="google搜索" onclick="window.open(s+document.all.q.value)"> <IFRAME border=0 name=play marginWidth=0 marginHeight=0 src=http://www1.xise.cn/baidu/140_80.htm frameBorder=0 width=140 scrolling=no height=80></IFRAME> <iframe scrolling="no" frameborder="0" width="150" height="25" src="http://www.xise.cn/qita/ip3.htm" allowtransparency="true"></iframe> <IFRAME border=0 name=play marginWidth=0 marginHeight=0 src=http://www1.xise.cn/tian.htm frameBorder=0 width=168 scrolling=no height=52></IFRAME> <br> <a href=' http://www.blogdove.com/' target='_blank'> 博鸽-最好用的好友博客阅读器<br><img src=' http://www.blogdove.com/images/logo.gif' /></a>
文章分类
IT专家
Bob大叔
Eric Newcomer
Martin Fowler's Bliki
夏昕的专栏
孟岩
林信良的专栏
良葛格学习笔记
Open-Source SOA Resource
bloger's SOA resource
open-source ESB petals
open-source esb ServiceMix
Service Oriented Business Integration
开源社区与论坛
Csdn社区
IBM Java开发者社区
ITPUB论坛
JavaEye
JavaResearchOrg
Java开源大全(全)
martinfowler大师的主页
Matrix与Java共舞
中国Eclipse社区
最重要的J2EE门户
面向Java/J2EE的软件站点
同事blog链接
TOM-Skype掌门人(RSS)
同学blog链接
xiaofeng同学
微笑的百合
文生
团队blog
bettyna
Cactus团队blog
李彦超
赵宁
存档

原创  也来玩转Skype ——基于Skype4Java API编写Skype外壳程序入门介绍 收藏

     Skype4Java API开发包官方下载地址:   

     https://developer.skype.com/wiki/Java_API

     在这篇文章中使用到了其中一个例子以及改进后的例子下载地址为:

    Skype4Java开发文档以及示例代码

     http://download.csdn.net/down/236693/lin_bei

Ø         Skype4Java架构

      Skype4Java提供了一个较为完善的开发体系,使您可以非常容易地使用Java

Skype外壳程序。Skype插件程序与Skype的通信都是基于一些文本命令来完

 

   因此,要想开发Skype的插件应用,就需要依靠不同操作系统平台的系统调

用,Skype平台的相应命令来实现。

   

   Skype4Java在最底层,也是通过操作系统的系统调用来完成消息的发送。针对

异构平台,Skype4Java提供了不同平台的底层实现,而Skype4Java的使用者不用

管具体的操作系统平台。因为抽象父类Connector类的静态方法getInstance()具体

判断当前操作系统是什么平台,采用简单的工厂模式,返回相应平台的子类对象,

OSXConnector.LinuxConnector, WindowsConnector, Win32Connector等,这

些都是Connector类的子类。Connector及其子类即实现了一些系统调用的方法,其

中被重载的一系列execute()方法最终调用不同子类的sendCommand (String

command)方法来实现了不同平台的消息发送。

  

    而对于一些数据的接收和处理全局都是采用事件监听的机制(观察者模式),

用于完成数据的接收,处理机制的调用,错误的处理等Skype平台利用错误消息机

制提供了出错的处理。因此,在我们的错误处理中,只需分析错误消息的内容,然

后通过观察者调用相应的处理机制即可。

   

    Skype4Java的实现是按照分层的方法来设计的,分层架构图如下所示。

    

       

Ø         Skype4Java命令发送示例

Skype提供了几种形式的开发接口给不同的语言,但有一个共同点就是,都是通过相同的命令(命令由命令标识符来标识,主要是在确认一个详细的请求命令以及响应消息时用的,每个命令及响应的消息ID是一样的,而且是唯一的),通过这样的方式来操作Skype。对于Skype4Java来说,命令的发送都是通过执行SKYPE4Java的抽象连接层(详细说明见后面),其中有一个核心类Connector的核心方法,原型为protected final String execute(final String command, final String[] responseHeaders, final boolean checkAttached),这个方法体里包含了保证与SKYPE处于连接状态,如果没连接会连接上,并且激发各种事件以及注册对这事件感兴趣的监听器。

public abstract class Connector {

……

protected final String execute(final String command, final String[] responseHeaders, final boolean checkAttached) throws ConnectorException {

    System.out.println("...准备执行命令...");

//先检验这次需要发送的命令,保证不为空

   ConnectorUtils.checkNotNull("command", command);

   ConnectorUtils.checkNotNull("responseHeaders", responseHeaders);

   //输出这次需要发送的命令的有关内容

 System.out.println("command: ->"+command);

        if (checkAttached){

//在发送之前得先保证客户端与Skype Client处于连接状态

          assureAttached();

        }

   //共享锁,因为这是一种请求-响应式的交互,正在执行此命令时要锁住程序专门

//处理这个命令的发送

        final Object lock = new Object();

   //命令的响应

        final String[] response = new String[1];

   //连接监听器的定义

        ConnectorListener listener = new AbstractConnectorListener() {

   //当命令发送后(下面的)完释放锁,客户程序将可以处理接收到的命令响应消

//,查看此命令的执行结果:System.out.println("response: <-"+message);

            public void messageReceived(ConnectorMessageEvent event) {

                String message = event.getMessage();

             System.out.println("response: <-"+message);

                for (String responseHeader : responseHeaders) {

                    if (message.startsWith(responseHeader)) {

                        response[0]=message;

    synchronized (lock) {

                            lock.notify();

                        }

                        return;

                    }

                }

            }

        };

//把上面定义的连接监听器注册到Connector

        addConnectorListener(listener, false);

//每次需要执行一个客户端命令时,都会调用fireMessageSent来激发所有注册进来

//的监听器

        fireMessageSent(command);

//发送命令的过程将会获得共享锁

        synchronized (lock) {

            try {

//调用不同子类的sendCommand方法来实现不同平台的消息发送.

                sendCommand(command);

     //获取发送命令时的当前时间

                long start = System.currentTimeMillis();

//获取命令发送超时的时间

                long commandResponseTime = getCommandTimeout();

//让共享锁锁住这个超时的时间那么长

lock.wait(commandResponseTime);

//判断是否超时

                if (commandResponseTime <= System.currentTimeMillis() - start) {

                    setStatus(Status.NOT_RUNNING);

                    throw new TimeOutException("The '" + command + "' command failed by timeout.");

                }

            } catch (InterruptedException e) {

                throw new ConnectorException("The '" + command + "' command was interrupted.");

            } finally {

   //移除监听器

                removeConnectorListener(listener);

            }

        }

        return response[0];

}

……

}

      SkypeCommandTest是一个Eclipse下的工程,解压后,直接导入到Eclipse中运行com.skype.test包中的ShowVersion.java类就可以看到命令的发送以及响应,结果为:

 

/*******************************************************************************

 * Copyright (c) 2006 Koji Hisano <hisano@gmail.com> - UBION Inc. Developer

 * Copyright (c) 2006 UBION Inc. <http://www.ubion.co.jp/> All rights reserved.

 *

 * Copyright (c) 2006 Skype Technologies S.A. <http://www.skype.com/>

 *

 * This program and the accompanying materials are made available under the

 * terms of the Common Public License v1.0 which accompanies this distribution,

 * and is available at http://www.eclipse.org/legal/cpl-v10.html

 *

 * Contributors: Koji Hisano - initial API and implementation

 ******************************************************************************/

package com.skype.test;

 

import com.skype.Skype;

 

public class ShowVersion {

    public static void main(String[] args) throws Exception {

          

        System.out.println(Skype.getVersion());

    }

}

 

代码中的关键语句是Skype.getVersion()。在这个方法中,首先是发送了”GET SKYPEVERSION”命令,此时并没有连接上Skype。再次发送”NAME SkypeAPI4Java”告知本应用程序的名字,最后发送”PROTOCOL 9999”来获取Skype协议版本,Skype返回版本号,比如:SKYPEVERSION 3.2.4.117

 

Ø         Skype4Java AP2AP示例

如果您需要利用Skype4JAVA开发AP2AP应用时,只需要通过Application对象创建某一个特定名称的应用,然后连接到也创建了此应用的联系人,连接时会返回一个Stream对象,此对象可用于发送基于TCPUDP的文本消息格式,然后通过注册的监听器处理返回消息(此监听器即是应用程序相关的,如您的网络游戏客户端),这样,就实现了通过Skype网络体系的AP2AP应用。

下面通过例子简单介绍一下AP2AP的流程。这段程序向所有的在使用同一Application的联系人发送一条文本消息:"*******HelloWorld!********" 并将对方利用Stream传递回来的文本消息打印到控制台。

 

package com.tom.test;

 

import com.skype.Application;

import com.skype.ApplicationAdapter;

import com.skype.Skype;

import com.skype.SkypeException;

import com.skype.Stream;

import com.skype.StreamAdapter;

 

public class AP2APTest {

   public static void main(String[] args) throws Exception {

          Skype.setDebug(true);

          Skype.setDeamon(false);

          //创建特名字的Application,并注册入Skype实例中

          Application application = Skype.addApplication(AP2APTest.class.getName());

          //添加应用监听器,当有相同的应用进行连接时,进行相应的处理

          application.addApplicationListener(new ApplicationAdapter() {

         //当有相同的应用与此应用连接时,此方法将被调用

              public void connected(Stream stream) throws SkypeException {

                  System.out.println("connected:" + stream.getId());

                  //添加Stream的监听器,完成对接收到的Stream里面的数据的处理,当然,用户可以根据需要添加方法,

                  //但需要改写Connector里面的相应代码

                  stream.addStreamListener(new StreamAdapter() {

                      @Override

                      //此方法完成对于对方传送数据的处理,也是基于SKYPE开发应用的入口点之一

                      public void textReceived(String receivedText) throws SkypeException {

                          System.out.println("received:" + Integer.toHexString(receivedText.length())+receivedText);

                      }

                  });

              }

          });

         //完成向所有联系人的请求连接,此方法返回Stream数组

         Stream[] streams=application.connectToAll();

         //向每一个注册了相同应用的SKYPE实例发送文本消息,也是基于SKYPE开发应用的入口点之一

         for(Stream stream: streams) {

             if(stream != null) {

                 stream.write("*******HelloWorld!********");

             }

         }

        

       

      }

}

 

首先,利用了ApplicationconnectToAll()方法连接所有的联系人,其中发送给Skype的文本消息如下:ALTER APPLICATION <appname> CONNECT <friendid>

   <appname>标识本application名称,比如:”ap2aptest”

   <friendid>标识待连接好友的Skype id

        connectToAll()方法将会返回一个Stream数组,对应每一个friendid ,都有一个唯一标识的Stream来维持通信,Stream用来完成数据的传送,利用Streamwrite(String text)方法即可向联系人发送一个文本消息。

为了处理从Stream发过来的消息,我们在Stream上注册了一个监听器:

stream.addStreamListener(new StreamAdapter() {

                 @Override

             public void textReceived(String receivedText) throws SkypeException {

                        System.out.println("received:" + receivedText);

                    }

                });

      一旦用户接收到来自于Stream的消息,即通过textReceivedString  receivedText)方法来处理。当您需要开发自己的应用时,完全可以向StreamAdapter中添加方法,然后做相应用的处理。因此在互为联系人的Skype用户两端运行这个程序,就完成了消息的发送和接收。

发表于 @ 2007年08月28日 16:18:00 | 评论( loading... ) | 编辑| 举报| 收藏

旧一篇:也来玩转Skype ——基于Skype4Com API编写Skype外壳程序 | 新一篇:l转:博鸽常见下载网址收录

  • 发表评论
  • 评论内容:
  •  
Copyright © lin_bei
Powered by CSDN Blog