Java 利用RXTX串口工具使用短信猫

由于前段时间做的系统需要使用短信猫收发短信,所以研究了一下在Java下使用短信猫,网上很多资料都是使用的smslib的jar包来发送短信,但是这种方式只支持32的jdk,而我的系统使用的是linux的64位环境,所以最后采用了用RXTX串口通讯工具直接向短信猫发送AT指令的方式实现。

1. smslib.jar收发短信

java调用短信猫发送短信。 这里的短信猫主要使用RS232串口与服务器通信。smslib.jar 需要用到java串口通信需要用到的comm.jar,win32com.dll和javax.comm.properties。
下载地址:短信猫java二次开发包smslib及使用示例
具体的使用可以参考短信猫java二次开发包源代码smslib-3.5.4.jar

2. RXTX串口通讯工具和短信猫收发短信关键代码

2.1. 短信猫串口通讯工具 rxtx-2.2pre2-bins

Win64位系统将RXTXcomm.jar拷贝到\jre\lib\ext目录下,win64文件夹中的rxtxSerial.dll 拷贝到\jre\bin 目录下。
Linux系统将RXTXcomm.jar拷贝/jre/lib/ext 目录下,librxtxSerial.so文件拷贝到 /jre/lib/[machine type] (i386 for instance) 中
若运行时找不到rxtxSerial 类,则拷贝到/usr/lib/jvm/java-6-sun-1.6.0.26(根据情况而定)/jre/lib/[machine type] (i386/amd64)
以上jre目录都已当前jre运行环境目录为准

2.2 将发送的短信进行PDU格式编码

package com.rxtx.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.sms.util.Convert;

/***
 * 发送pdu格式短信工具
 */
public class SendUtil {
    static String regEx = "[\u4e00-\u9fa5]";//中文
    static Pattern pat = Pattern.compile(regEx);
    public static void main(String[] args) throws Exception {
        String text =encodeHex("test");
        System.out.print(text);
    }
    /**
     * 使用PDU方式发送消息 
     * @param phone
     * @param msg
     * @return AT指令
     */
    public static final String PDUEncoder(String phone,String msg){
        String sendcontent ="";
        String len="";
        if(isContainsChinese(msg)){ //短信包含中文
            sendcontent= "0011000D91" + reverserNumber(phone) + "000801" + PDUUSC2ContentEncoder(msg) ;
        }else{
            sendcontent= "0011000D91" + reverserNumber(phone) + "000001" + PDU7BitContentEncoder(msg) ;
        }
        len = (sendcontent.length() - Integer.parseInt(sendcontent.substring(0, 2), 16) * 2 - 2) / 2 +"";  //计算长度
        if(len.length()<2) len="0"+len;
//      return "AT+CMGS=" + len + "\r" + sendcontent + String.valueOf(26);  //26 Ctrl+Z ascii码
        return len+","+sendcontent;
    }
    /**
     * 获取短信内容的字节数
     * @param txt
     * @return
     */
    private static String getLength(String txt)
    {
        int i = 0;
        String s = "";
        i = txt.length() * 2;
        i += 15;
        s = i+"";
        return s;
    }
    /**
     * 将手机号码转换为内存编码
     * @param phone
     * @return
     */
    private static String reverserNumber(String phone)
    {
        String str = "";
        //检查手机号码是否按照标准格式写,如果不是则补上
        if (phone.substring(0, 2) != "86")
        {
            phone = "86"+phone;
        }
        char[] c = getChar(phone);
        for (int i = 0; i <= c.length - 2; i += 2)
        {
            str += c[i + 1]+"" + c[i];
        }
        return str;
    }

    private static char[] getChar(String phone)
    {
        if (phone.length() % 2 == 0)
        {
            return phone.toCharArray();
        }
        else
        {
            return (phone + "F").toCharArray();
        }
    }

    private static boolean isContainsChinese(String str)
    {
        Matcher matcher = pat.matcher(str);
        boolean flg = false;
        if (matcher.find())    {
            flg = true;
        }
        return flg;
    }
    /**
     * 使用Sms 的 SendSms()方法发送短信时,调用此方法将其短信内容转换成十六进制
     * @param msg 短信内容
     * @return 转换后的十六进制短信
     */
    public static final String encodeHex(String msg) {
        byte[] bytes = null;
        try {
            bytes = msg.getBytes("GBK");
        } catch (java.io.UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        StringBuffer buff = new StringBuffer(bytes.length * 4);
        String b = "";
        char a;
        int n = 0;
        int m = 0;
        for (int i = 0; i < bytes.length; i++) {
            try{b = Integer.toHexString(bytes[i]);}catch (Exception e) {}
            if (bytes[i] > 0) {
                buff.append("00");
                buff.append(b);
                n = n + 1;
            } else {
                a = msg.charAt((i - n) / 2 + n);
                m = a;
                try{b = Integer.toHexString(m);}catch (Exception e) {}
                buff.append(b.substring(0, 4));

                i = i + 1;
            }
        }
        return buff.toString();
    }
    /**
     * 中文短信内容USC2编码
     * @param userData
     * @return
     */
    private static String PDUUSC2ContentEncoder(String userData){
        String contentEncoding = encodeHex(userData);
        String length = Integer.toHexString(contentEncoding.length() / 2);//把value的值除以2并转化为十六进制字符串
        while(length.length()<2) length="0"+length;
        return length+contentEncoding.toUpperCase();

    }
    /**
     * 英文短信内容7Bit编码
     * @param userData
     */
    public static String PDU7BitContentEncoder(String userData) {
        String result = "";
        String length = Integer.toHexString(userData.length());
        while(length.length()<2) length="0"+length;//7bit编码 用户数据长度:源字符串长度

        byte[] Bytes = userData.getBytes();

        String temp = "";                                     //存储中间字符串 二进制串
        String tmp;
        for (int i = userData.length(); i > 0; i--) {
            tmp = Convert.conver2HexStr(Bytes[i-1]);
            while (tmp.length() < 7) {
                tmp = "0" + tmp;
            }
            temp += tmp;
        }
        for (int i = temp.length() ; i > 0; i -= 8) {                   //每8位取位一个字符 即完成编码 同时高位取为低位
            if (i > 8) {
                String aa = Integer.toHexString(Integer.parseInt(temp.substring(i-8, i), 2));
                while(aa.length()<2) aa="0"+aa;
                result += aa;
            } else {
                String aa = Integer.toHexString(Integer.parseInt(temp.substring(0, i), 2));
                while(aa.length()<2) aa="0"+aa;
                result += aa;
            }
        }
        return length+result.toUpperCase();
    }
}

2.3 以text形式发送短信时短信编码成16进制

/**
     * 将其短信内容转换成十六进制
     * @param msg 短信内容
     * @return 转换后的十六进制短信
     */
    public static final String encodeHex(String msg) {
        byte[] bytes = null;
        try {
            bytes = msg.getBytes("GBK");
        } catch (java.io.UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        StringBuffer buff = new StringBuffer(bytes.length * 4);
        String b = "";
        char a;
        int n = 0;
        int m = 0;
        for (int i = 0; i < bytes.length; i++) {
            try{b = Integer.toHexString(bytes[i]);}catch (Exception e) {}
            if (bytes[i] > 0) {
                buff.append("00");
                buff.append(b);
                n = n + 1;
            } else {
                a = msg.charAt((i - n) / 2 + n);
                m = a;
                try{b = Integer.toHexString(m);}catch (Exception e) {}
                buff.append(b.substring(0, 4));

                i = i + 1;
            }
        }
        return buff.toString();
    }

2.4 接收短信时解析接收的字符串

/**
     * 解析MODEM返回来的字符串
     * 根据MODEM返回的字符串,解析成一个CommonSms的集合对象
     * @param str MODEM返回的字符串
     * @return
     */
    public static List<CommonSms> analyseArraySMS(String str) {
        List<CommonSms> mesList = new ArrayList<CommonSms>();
        CommonSms cs;
        String[] messages;
        String temp;
        String[] t;
        if (str.indexOf("CMGL: ") == -1)
            return null;
        str = str.substring(0, str.indexOf("OK")).trim();
        messages = str.split("\n");
        if (messages.length < 2)
            return null;
        for (int i = 0; i < messages.length; i++) {
            cs = new CommonSms();
            if(messages[i].length()>=messages[i].indexOf("CMGL: ")+6){
                messages[i] = messages[i]
                                    .substring(messages[i].indexOf("CMGL: ") + 6);
            }           
            t = messages[i].split(",");
            //CT5150
            if (t.length > 5) {
                t[0] = t[0].replaceAll(":", "");
                cs.setId(Integer.parseInt(t[0].trim()));
                temp = t[1].substring(t[1].indexOf('"') + 1,
                        t[1].lastIndexOf('"')).trim();
                if (temp.equals("REC READ")) {
                    cs.setState("已读");
                } else {
                    cs.setState("未读");
                }
                cs.setSender((t[2].substring(t[2].indexOf('"') + 1, t[2]
                        .lastIndexOf('"')).trim()));
                //CT5150
                SimpleDateFormat df = new SimpleDateFormat("yy/MM/dd hh:mm:ss");
                String datestring = t[4].substring(t[4].indexOf('"') + 1) + " "
                        + t[5].substring(0, t[5].indexOf('"'));// 短信猫时间格式09/09/09
                                                                // 20:18:01+32
                Date date = null;
                try {
                    date = df.parse(datestring);
                } catch (Exception ex) {
                    System.out.println(ex.getMessage());
                }
                cs.setDate(date);
                i++;
                cs.setSmstext(analyseStr(messages[i].trim()));
                mesList.add(cs);
            }
        }
        return mesList;
    }

/**
     * 将编码的十六进制字符串 如“4F60597DFF01” 转换成unicode "\u4F60\u597D\uFF01"
     * @param str 要转化的字符串
     * @return 转换后的十六进制字符串
     */
    public static String analyseStr(String str) {
        StringBuffer sb = new StringBuffer();
        if (!(str.length() % 4 == 0))
            return str;
        for (int i = 0; i < str.length(); i++) {
            if (i == 0 || i % 4 == 0) {
                sb.append("\\u");
            }
            sb.append(str.charAt(i));
        }
        return Unicode2GBK(sb.toString());
    }

/**
     * 将unicode编码 "\u4F60\u597D\uFF01" 转换成中文 "你好!"
     * @param dataStr 要转化的字符串
     * @return 转换后的中文字符串
     */
    public static String Unicode2GBK(String dataStr) {
        int index = 0;
        StringBuffer buffer = new StringBuffer();
        while (index < dataStr.length()) {
            if (!"\\u".equals(dataStr.substring(index, index + 2))) {
                buffer.append(dataStr.charAt(index));
                index++;
                continue;
            }
            String charStr = "";
            charStr = dataStr.substring(index + 2, index + 6);
            char letter = 0;
            try{letter = (char) Integer.parseInt(charStr, 16);}catch (Exception e) {}
            buffer.append(letter);
            index += 6;
        }
        return buffer.toString();
    }

2.5 发送和接收短信

这里发送短信的设置是,发送英文短信时使用PDU编码,发送中文时使用Text模式发送,这是因为英文短信只有使用PDU编码才会在接收时被识别为英文(这是开发时实践得出的并不知道是为什么)。

private CommonSms commonsms;
    private static char symbol1 = 13;
    private static String strReturn = "", atCommand = "";

/**
     * 号码,内容,发送短信息
     * @param phone
     * @param countstring
     * @throws Exception
     */
    public static void sendmsn(String phone,String countstring){
         Sms s = new Sms();
          // 发送测试       
          CommonSms cs=new CommonSms();
          cs.setRecver(phone);
          cs.setSmstext(countstring);
          s.setCommonsms(cs);
          Port myort=new Port("COM4");
          System.out.println(myort.isIsused()+"     "+myort.getCOMname());
         s.SendSms(myort,0);    
         s.setMessageMode(myort,1);
          List<CommonSms> recvlist = s.RecvSmsList(myort);
          if(recvlist!=null){
              for(CommonSms sms:recvlist){
                  System.out.println("发送人:"+sms.getSender()+"  时间:"+sms.getDate()+"  状态:"+sms.getState());
                  System.out.println("内容:"+sms.getSmstext());
              }
          }
          myort.close();
    }

    public boolean SendSms(Port myport,int op) {
        if(!myport.isIsused())
        {       
        System.out.println("COM通讯端口未正常打开!");        
        return false;
        }
        setMessageMode(myport,op);
        // 空格
        char symbol2 = 34;
        // ctrl~z 发送指令
        char symbol3 = 26;
        try {
            if(op==1){
                atCommand = "AT+CSMP=17,169,0,08" + String.valueOf(symbol1);
                strReturn = myport.sendAT(atCommand);
                System.out.println(strReturn);
                if (strReturn.indexOf("OK", 0) != -1) {
                    atCommand = "AT+CMGS=" + commonsms.getRecver()
                            + String.valueOf(symbol1);
                    strReturn = myport.sendAT(atCommand);
                    atCommand = StringUtil.encodeHex(commonsms.getSmstext().trim())
                            + String.valueOf(symbol3) + String.valueOf(symbol1);
                    strReturn = myport.sendAT(atCommand);
                    if (strReturn.indexOf("OK") != -1
                            && strReturn.indexOf("+CMGS") != -1) {
                        System.out.println("短信发送成功...");
                        return true;
                    }
                }   
            }else if(op==0){
                String[] txt = SendUtil.PDUEncoder(commonsms.getRecver(), commonsms.getSmstext().trim()).split(",");
                atCommand = "AT+CMGS=" + txt[0] + String.valueOf(symbol1);
                strReturn = myport.sendAT(atCommand);
                strReturn = myport.sendAT(txt[1]+ String.valueOf(symbol3) + String.valueOf(symbol1));
                if (strReturn.indexOf("OK") != -1
                        && strReturn.indexOf("+CMGS") != -1) {
                    System.out.println("短信发送成功...");
                    return true;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();           
            System.out.println("短信发送失败...");        
            return false;
        }   
        System.out.println("短信发送失败...");    
        return false;
    }
    /**
     * 设置消息模式 
     * @param op
     * 0-pdu 1-text(默认1 文本方式 )
     * @return
     */
    public boolean setMessageMode(Port myport,int op) {
        try {
            String atCommand = "AT+CMGF=" + String.valueOf(op)
                    + String.valueOf(symbol1);
            String  strReturn = myport.sendAT(atCommand);
            if (strReturn.indexOf("OK", 0) != -1) {
                System.out.println("*************消息模式 设置成功************");
                return true;
            }
            return false;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }   

    /**
    * 读取所有短信 
    * @return CommonSms集合
    */
    public List<CommonSms> RecvSmsList(Port myport) {
        if(!myport.isIsused())
        {
            System.out.println("System Message:  COM通讯端口未正常打开!");       
            return null;
        }
        List<CommonSms> listMes = new ArrayList<CommonSms>();
        try {
            atCommand = "AT+CMGL=\"REC UNREAD\"";
//          atCommand = "AT+CMGL=\"ALL\"";
//          AT+CMGL="REC UNREAD"代表显示未读短信清单
//                     AT+CMGL= "REC READ"代表显示已读短信清单
//                     AT+CMGL= "STO SENT"代表显示已发送的存储短信清单
//                     AT+CMGL= "STO UNSENT"代表显示未发送的存储短信清单
//                     AT+CMGL= "ALL"代表显示所有短信清单
            strReturn = myport.sendAT(atCommand);
            if(strReturn.contains("ERROR"))
            System.out.println("System Message:  读取短信出错!");
            listMes = StringUtil.analyseArraySMS(strReturn);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return listMes;
    }

3. 短信猫串口相关问题

在使用短信猫时要填写短信猫的串口号,windows下很方便查看,直接填写COM4或者其他的就行,在linux下就有一点麻烦,下面介绍一下我在部署程序时查看串口号的方法,给大家一个参考。

(1)短信猫使用串口转usb连接服务器,那么端口可能是ttyUSB0
直接 ls /dev 查看设备信息,找到ttyUSB*,进而判断短信猫的串口
(2)tail -10 /var/log/messages 可以查看硬件设备插拔变化,查看短信猫是哪个设备
(3)短信猫直接通过串口连接服务器的话
# dmesg | grep tty 或者 setserial -g /dev/ttyS* 显示检测到的系统串口支持

一个简单示例:短信猫用rxtx收发短信Java示例
本文示例:Java 利用RXTX串口工具使用短信猫

猜你喜欢

转载自blog.csdn.net/my_tiantian/article/details/77775648
今日推荐