`
sjsky
  • 浏览: 904920 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SMSLib实现Java短信收发的功能

阅读更多
    blog迁移至:http://www.micmiu.com

    用java实现短信收发的功能,目前一般项目中短信群发功能的实现方法大致有下面三种:
  • 1、 向运行商申请短信网关,不需要额外的设备,利用运行商提供的API调用程序发送短信,适用于大型的通信公司。
  • 2、 借助像GSM MODEM之类的设备(支持AT指令的手机也行),通过数据线连接电脑来发送短信,这种方法比较适用于小公司及个人。要实现这种方式必须理解串口通信、AT指令、短信编码、解码。
  • 3、 借助第三方运行的网站实现,由网站代发短信数据,这种方法对网站依赖性太高,对网络的要求也比较高。

       鉴于项目的情况和多方考虑,同时又找到了一个开源的SMSLib项目的支持,比较倾向于第二种方法,SMSLib的出现就不需要我们自己去写底层的AT指令,这样就可以直接通过调用SMSLib的API来实现通过GSM modem来收发送短信了。

SMSLib官方网站:http://smslib.org/,使用SMSLib的一些基本要点:
  • SUN JDK 1.6 or newer. (Java环境)
  • Java Communications Library. (Java串口通信)
  • Apache ANT for building the sources. (编译源码时需要的)
  • Apache log4j. (日志工具)
  • Apache Jakarta Commons - NET. (网络操作相关的)
  • JSMPP Library (SMPP协议时需要的)

有关Java串口通信需要补充说明:

附件提供相关下载:

本次测试的环境是window,GSM modem是wavecom,所以这次主要描述window环境下简单的实现过程:
【一】、配置相应的环境
      首先解压下载的Java Comm v2文件javacomm20-win32.zip,具体配置步骤如下:
  • 把文件:comm.jar copy 到目录:<JDKDIR>/jre/lib/ext/,当然这一步也可以不要这样做,你只需把comm.jar copy到所要运行的项目对应的lib/下既可
  • 把文件:javax.comm.properties copy 到目录:<JDKDIR>/jre/lib/
  • 把DLL文件:win32com.dll(windows) copy 到目录:<JDKDIR>/jre/bin/
  • 如果存在JRE目录, 最好按照上面步骤把文件copy到<JREDIR>相应的目录下

【二】、测试串口端口程序:
TestGetPortList.java
package michael.comm.serial;

import java.util.Enumeration;

import javax.comm.CommDriver;
import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;

/**
 * @author michael
 * 
 */
public class TestGetPortList {

    /**
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // 人工加载驱动
        // MainTest.driverInit();
        TestGetPortList.getCommPortList();
        // 人工加载驱动获取端口列表
        // TestGetPortList.getPortByDriver();

    }

    /**
     * 手工加载驱动<br>
     * 正常情况下程序会自动加载驱动,故通常不需要人工加载<br>
     * 每重复加载一次,会把端口重复注册,CommPortIdentifier.getPortIdentifiers()获取的端口就会重复
     */
    public static void driverManualInit() {
        String driverName = "com.sun.comm.Win32Driver";
        String libname = "win32com";
        CommDriver commDriver = null;
        try {
            System.loadLibrary("win32com");
            System.out.println(libname + " Library Loaded");

            commDriver = (javax.comm.CommDriver) Class.forName(driverName)
                    .newInstance();
            commDriver.initialize();
            System.out.println("comm Driver Initialized");

        } catch (Exception e) {
            System.err.println(e);
        }
    }

    /**
     * 获取端口列表
     */
    public static void getCommPortList() {
        CommPortIdentifier portId;
        Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
        while (portEnum.hasMoreElements()) {
            portId = (CommPortIdentifier) portEnum.nextElement();

            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                System.out.println("串口: name-" + portId.getName()
                        + " 是否占用-" + portId.isCurrentlyOwned());
            } else {
                System.out.println("并口: name-" + portId.getName()
                        + " 是否占用-" + portId.isCurrentlyOwned());
            }
        }
        System.out.println("-------------------------------------");
    }

    /**
     * 
     */
    public static void getPortByDriver() {

        String driverName = "com.sun.comm.Win32Driver";
        String libname = "win32com";
        CommDriver commDriver = null;
        try {
            System.loadLibrary("win32com");
            System.out.println(libname + " Library Loaded");

            commDriver = (CommDriver) Class.forName(driverName).newInstance();
            commDriver.initialize();
            System.out.println("comm Driver Initialized");

        } catch (Exception e) {
            System.err.println(e);
        }
        SerialPort sPort = null;
        try {

            sPort = (SerialPort) commDriver.getCommPort("COM24",
                    CommPortIdentifier.PORT_SERIAL);
            System.out.println("find CommPort:" + sPort.toString());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }

}

本机运行结果:
引用

串口: name-COM10 是否占用-false
串口: name-COM21 是否占用-false
串口: name-COM23 是否占用-false
串口: name-COM20 是否占用-false
串口: name-COM22 是否占用-false
串口: name-COM24 是否占用-false
串口: name-COM9 是否占用-false
串口: name-COM19 是否占用-false
串口: name-COM3 是否占用-false
串口: name-COM8 是否占用-false
串口: name-COM98 是否占用-false
串口: name-COM99 是否占用-false
串口: name-COM4 是否占用-false
串口: name-COM5 是否占用-false
串口: name-COM6 是否占用-false
并口: name-LPT1 是否占用-false
并口: name-LPT2 是否占用-false
-------------------------------------

【三】、检查串口设备信息:
TestCommPort.java
package michael.comm.serial;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;

import javax.comm.CommPortIdentifier;
import javax.comm.SerialPort;

/**
 * @author michael
 * 
 */
public class TestCommPort {
    static CommPortIdentifier portId;
    static Enumeration portList;
    static int bauds[] = { 9600, 19200, 57600, 115200 };

    /**
     * @param args
     */
    public static void main(String[] args) {
        portList = CommPortIdentifier.getPortIdentifiers();
        System.out.println("GSM Modem 串行端口连接测试开始...");
        String portName = "COM24";
        while (portList.hasMoreElements()) {
            portId = (CommPortIdentifier) portList.nextElement();
            if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL
                    && portName.equals(portId.getName())) {
                System.out.println("找到串口: " + portId.getName());
                for (int i = 0; i < bauds.length; i++) {
                    System.out.print("  Trying at " + bauds[i] + "...");
                    try {
                        SerialPort serialPort;
                        InputStream inStream;
                        OutputStream outStream;
                        int c;
                        StringBuffer response = new StringBuffer();
                        serialPort = (SerialPort) portId.open(
                                "SMSLibCommTester", 2000);
                        serialPort
                                .setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN);
                        serialPort.setSerialPortParams(bauds[i],
                                SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                                SerialPort.PARITY_NONE);
                        inStream = serialPort.getInputStream();
                        outStream = serialPort.getOutputStream();
                        serialPort.enableReceiveTimeout(1000);
                        c = inStream.read();
                        while (c != -1) {
                            c = inStream.read();
                        }
                        outStream.write('A');
                        outStream.write('T');
                        outStream.write('\r');
                        try {
                            Thread.sleep(1000);
                        } catch (Exception e) {
                        }
                        c = inStream.read();
                        while (c != -1) {
                            response.append((char) c);
                            c = inStream.read();
                        }
                        if (response.indexOf("OK") >= 0) {
                            System.out.print("  正在检测设备:");
                            try {
                                outStream.write('A');
                                outStream.write('T');
                                outStream.write('+');
                                outStream.write('C');
                                outStream.write('G');
                                outStream.write('M');
                                outStream.write('M');
                                outStream.write('\r');
                                response = new StringBuffer();
                                c = inStream.read();
                                while (c != -1) {
                                    response.append((char) c);
                                    c = inStream.read();
                                }
                                System.out.println("  发现设备: "
                                        + response.toString().replaceAll(
                                                "(\\s+OK\\s+)|[\n\r]", ""));
                            } catch (Exception e) {
                                System.out.println("  检测设备失败,获取设备信息异常:"
                                        + e.getMessage());
                            }
                        } else {
                            System.out.println("  检测设备失败,沒有接收到响应结果!");
                        }
                        serialPort.close();
                    } catch (Exception e) {
                        System.out.println("  检测设备失败,发生异常:" + e.getMessage());
                    }
                }
            }
        }
    }
}

运行结果如下:
引用

GSM Modem 串行端口连接测试开始...
找到串口: COM24
  Trying at 9600...  正在检测设备:  发现设备: AT+CGMM MULTIBAND  900E  1800
  Trying at 19200...  发现设备失败,沒有接收到响应结果!
  Trying at 57600...  发现设备失败,沒有接收到响应结果!
  Trying at 115200...  发现设备失败,沒有接收到响应结果!


【四】、测试收发短信:
package michael.sms;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.smslib.AGateway;
import org.smslib.GatewayException;
import org.smslib.InboundMessage;
import org.smslib.OutboundMessage;
import org.smslib.Service;
import org.smslib.AGateway.Protocols;
import org.smslib.Message.MessageEncodings;
import org.smslib.modem.SerialModemGateway;

/**
 * @author michael
 * 
 */
public class SmsHandler {
    private static final Logger logger = Logger.getLogger(SmsHandler.class);

    private Service smsService;

    /**
     * 
     */
    public SmsHandler() {
        smsService = Service.getInstance();
        List<AGateway> agatewayList = new ArrayList<AGateway>();

        String portName = "COM24";//"/dev/ttyUSB0";// COM24
        SerialModemGateway gateway = new SerialModemGateway(
                "modem." + portName, portName, 9600, "wavecom", "PL2303");
        gateway.setInbound(true);
        gateway.setOutbound(true);
        gateway.setProtocol(Protocols.PDU);
        gateway.setSimPin("0000");
        agatewayList.add(gateway);
        try {
            for (AGateway gatewayTmp : agatewayList) {
                smsService.addGateway(gatewayTmp);
            }
        } catch (GatewayException ex) {
            logger.error(ex.getMessage());
        }
    }

    /**
     * 
     */
    public void start() {
        logger.info("SMS service start.....");
        try {
            smsService.startService();
        } catch (Exception ex) {
            logger.error("SMS service start error:", ex);
        }
    }

    /**
     * 
     */
    public void destroy() {
        try {
            smsService.stopService();
        } catch (Exception ex) {
            logger.error("SMS service stop error:", ex);
        }
        logger.info("SMS service stop");
    }

    /**
     * send SMS
     * @param msg
     * @return Boolean
     */
    public Boolean sendSMS(OutboundMessage msg) {
        try {
            msg.setEncoding(MessageEncodings.ENCUCS2);
            return smsService.sendMessage(msg);
        } catch (Exception e) {
            logger.error("send error:", e);
        }
        return false;
    }

    private boolean isStarted() {
        if (smsService.getServiceStatus() == Service.ServiceStatus.STARTED) {
            for (AGateway gateway : smsService.getGateways()) {
                if (gateway.getStatus() == AGateway.GatewayStatuses.STARTED) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * read SMS
     * @return List
     */
    public List<InboundMessage> readSMS() {
        List<InboundMessage> msgList = new LinkedList<InboundMessage>();
        if (!isStarted()) {
            return msgList;
        }
        try {
            this.smsService.readMessages(msgList,
                    InboundMessage.MessageClasses.ALL);
            logger.info("read SMS size: " + msgList.size());
        } catch (Exception e) {
            logger.error("read error:", e);
        }
        return msgList;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        Logger.getRootLogger().setLevel(Level.INFO);
        OutboundMessage outMsg = new OutboundMessage("189xxxx****", "信息测试");
        SmsHandler smsHandler = new SmsHandler();
        smsHandler.start();
        //发送短信
        smsHandler.sendSMS(outMsg);
        //读取短信
        List<InboundMessage> readList = smsHandler.readSMS();
        for (InboundMessage in : readList) {
            System.out.println("发信人:" + in.getOriginator() + " 短信内容:"
                    + in.getText());
        }
        smsHandler.destroy();
        System.out.println("-----------");
    }

}

发送短信亲测,手机能正常接收显示。读取设备的短信程序运行结果结果如下:
引用

INFO - Service.listSystemInformation(113) | SMSLib: A Java API library for sending and receiving SMS via a GSM modem or other supported gateways.
This software is distributed under the terms of the Apache v2.0 License.
Web Site: http://smslib.org
INFO - Service.listSystemInformation(114) | Version: 3.5.1
INFO - Service.listSystemInformation(115) | JRE Version: 1.6.0_18
INFO - Service.listSystemInformation(116) | JRE Impl Version: 16.0-b13
INFO - Service.listSystemInformation(117) | O/S: Windows Vista / x86 / 6.0
INFO - SmsHandler.start(55) | SMS service start.....
INFO - DefaultQueueManager.init(92) | Queue directory not defined. Queued messages will not be saved to filesystem.
INFO - ModemGateway.startGateway(188) | GTW: modem.COM24: Starting gateway, using Generic AT Handler.
INFO - SerialModemDriver.connectPort(68) | GTW: modem.COM24: Opening: COM24 @9600
INFO - AModemDriver.waitForNetworkRegistration(459) | GTW: modem.COM24: GSM: Registered to foreign network (roaming).
INFO - AModemDriver.connect(175) | GTW: modem.COM24: MEM: Storage Locations Found: SMBM
INFO - CNMIDetector.getBestMatch(142) | CNMI: No best match, returning: 1
INFO - ModemGateway.startGateway(191) | GTW: modem.COM24: Gateway started.
INFO - SmsHandler.readSMS(113) | read SMS size: 1
发信人:8618918001030 短信内容:hello 回复测试

INFO - ModemGateway.stopGateway(197) | GTW: modem.COM24: Stopping gateway...
INFO - SerialModemDriver.disconnectPort(120) | GTW: modem.COM24: Closing: COM24 @9600
INFO - ModemGateway.stopGateway(201) | GTW: modem.COM24: Gateway stopped.
INFO - SmsHandler.destroy(72) | SMS service stop
-----------


-----------------------------------分 ------------------------------------隔 ------------------------------------线 --------------------------------------
8
3
分享到:
评论
11 楼 liaq_529 2013-02-26  
我的为什么找不到串口。。。
10 楼 evil850209 2012-09-24  
如何调用usb端口的设备呢?我这只能显示出来COM1口,其他的串口都没有
9 楼 chensong215 2012-07-20  
chensong215 写道
用厦门宇能的短信 猫,调用InboundMessage的getText()方法就出错了,提示不支持

不知各位有没有遇到过?是怎么解决的?
8 楼 chensong215 2012-07-20  
用厦门宇能的短信 猫,调用InboundMessage的getText()方法就出错了,提示不支持
7 楼 sjsky 2012-05-06  
liminshaoye 写道
第二次会发送失败发送不了?请问怎么解决?

你说的“第二次”,不知道你是指通一条短信发两次 还是 重复调用发送的 方法 失败
6 楼 liminshaoye 2012-05-05  
第二次会发送失败发送不了?请问怎么解决?
5 楼 liminshaoye 2012-05-05  
为什么不能重复发送短信?
4 楼 xiaoLee 2012-04-24  
封装的不错
3 楼 jjyuan 2012-03-31  
2 楼 glearner 2011-09-27  
好像还需要一个log4j.properties的文件!才能调试通过,不过一次发送成功过后,第二次com就会被smslib占用,不能发送成功会抛出异常。不知道什么原因?
1 楼 gyspring 2011-08-27  

相关推荐

Global site tag (gtag.js) - Google Analytics