首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java SMSLib 串口短信貓發送與接收短信完整實戰:Gateway 配置、PDU 模式、中文編碼

     編輯:Java 程式設計入門

專案背景

在物聯網、警報通知、驗證碼等場景,透過 GSM/3G/4G 短信貓(Modem) 經串口(COM/USB 轉串口)發送短信是經典方案。SMSLib v3 是 Java 領域最成熟的短信庫,支援 AT 指令封裝、PDU/文本模式、多 Gateway 管理、異步事件通知。本範例完整展示 SerialModemGateway 配置、發送中文短信(UCS2 編碼)、接收短信、來電通知三大核心功能。

核心類別架構

public class SmsModem {
    private SerialModemGateway gateway;
    private Service srv;                    // SMSLib 核心服務
    private OutboundNotification outboundNotification;
    private InboundNotification inboundNotification;
    private CallNotification callNotification;
    // ... 單例模式 getInstant()
}

關鍵初始化流程

public SmsModem() {
    try {
        // 1. 讀取配置(ResourceBundle 讀取 sms.properties)
        ResourceBundle rb = ResourceBundle.getBundle("sms");
        String portName = "COM10";  // 預設
        int baudRate = 9600;
        if (rb != null) {
            portName = rb.getString("smsport");
            baudRate = Integer.parseInt(rb.getString("smsbolv"));
        }

        // 2. 建立 SerialModemGateway
        // 參數:gatewayId、portName、baudRate、製造商、型號
        gateway = new SerialModemGateway("modem." + portName, portName, baudRate,
                "wavecom", "17254"); // 製造商/型號用於 AT+CGMI/AT+CGMM 識別

    } catch (Exception e) {
        LOG.error("Gateway 初始化失敗", e);
    }
}

服務啟動與 Gateway 綁定

private void ensureServiceStarted() throws Exception {
    if (srv == null) {
        srv = new Service();
        srv.S.SERIAL_POLLING = true; // 啟用串口輪詢

        gateway.setInbound(true);    // 啟用接收
        gateway.setOutbound(true);   // 啟用發送
        gateway.setSimPin("0000");   // SIM PIN 碼(若無鎖可空)

        // 3. 註冊三大回調
        gateway.setOutboundNotification(outboundNotification); // 發送狀態報告
        gateway.setInboundNotification(inboundNotification);   // 收到短信
        gateway.setCallNotification(callNotification);         // 來電

        srv.addGateway(gateway);
        srv.startService(); // 關鍵:開啟串口、啟動輪詢執行緒
    }
}

發送中文短信(核心:UCS2 編碼)

public void doIt(String phone, String content) throws Exception {
    ensureServiceStarted();

    // 印出 Modem 資訊(診斷用)
    LOG.info("Manufacturer: " + gateway.getManufacturer());
    LOG.info("Model: " + gateway.getModel());
    LOG.info("Signal: " + gateway.getSignalLevel() + "%");

    // 4. 建立發送訊息
    OutboundMessage msg = new OutboundMessage(phone, content);
    msg.setEncoding(Message.MessageEncodings.ENCUCS2); // 關鍵!中文必須 UCS2 (UTF-16BE)
    // 若不設定,預設 GSM 7-bit,中文會亂碼或截斷

    // 5. 同步發送
    srv.sendMessage(msg);
}

三大回調實現

1. 發送狀態報告

public class OutboundNotification implements IOutboundMessageNotification {
    public void process(String gatewayId, OutboundMessage msg) {
        LOG.info("發送狀態回報 - Gateway: " + gatewayId);
        LOG.info("狀態: " + msg.getStatus() + " | 參考號: " + msg.getRefNo());
    }
}

2. 接收短信

public class InboundNotification implements IInboundMessageNotification {
    public void process(String gatewayId, Message.MessageTypes msgType, InboundMessage msg) {
        if (msgType == Message.MessageTypes.INBOUND) {
            LOG.info("收到新短信 - 來自: " + msg.getOriginator());
            LOG.info("內容: " + msg.getText());
            LOG.info("時間: " + msg.getDate());
            // 可選:自動刪除已讀短信釋放 SIM 空間
            // srv.deleteMessage(msg);
        } else if (msgType == Message.MessageTypes.STATUSREPORT) {
            LOG.info("收到狀態報告: " + msg.getStatus());
        }
    }
}

3. 來電通知

public class CallNotification implements ICallNotification {
    public void process(String gatewayId, String callerId) {
        LOG.info("來電 - Gateway: " + gatewayId + " | 主叫: " + callerId);
        // 可觸發業務邏輯:彈窗、錄音、掛斷等
    }
}

主動讀取歷史短信

public String readMessage() {
    StringBuilder sb = new StringBuilder();
    try {
        ensureServiceStarted();
        List<InboundMessage> msgList = new ArrayList<>();
        srv.readMessages(msgList, InboundMessage.MessageClasses.ALL); // ALL/UNREAD/READ/SENT

        int i = 1;
        for (InboundMessage msg : msgList) {
            sb.append("第").append(i).append("條;發件人:")
              .append(msg.getOriginator()).append(";內容:")
              .append(msg.getText()).append("\n");
            i++;
        }
    } catch (Exception e) {
        sb.append("讀取失敗: ").append(e.getMessage());
    }
    return sb.toString();
}

關鍵配置檔 sms.properties

# 串口號(Windows: COMx, Linux: /dev/ttyUSBx)
smsport=COM10
# 波特率(常見:9600, 115200, 460800)
smsbolv=9600

硬體與 AT 指令驗證清單

步驟AT 指令預期回應
基本通訊ATOK
查詢製造商AT+CGMIWavecom / Huawei / SIMCom 等
查詢型號AT+CGMM具體型號
查詢訊號AT+CSQ+CSQ: 15,99 (0-31, 越大越好)
查詢 SIM 狀態AT+CPIN?+CPIN: READY
設定 PDU 模式AT+CMGF=0OK
設定短信中心號碼AT+CSCA="+861380xxxxxxx"OK
發送測試AT+CMGS=... (PDU 封裝)+CMGS: <mr>

常見坑點與解決方案

  • 中文亂碼:必須 msg.setEncoding(ENCUCS2),且確認 Modem 支援 UCS2(絕大多數現代模組支援)。
  • 串口佔用/權限:Linux 需 sudo usermod -a -G dialout $USER 或 chmod 666 /dev/ttyUSB0。
  • 波特率不匹配:嘗試 9600/115200/460800,或用 AT+IPR=9600 固定。
  • SIM PIN 鎖定:gateway.setSimPin("1234") 或 AT+CPIN="1234" 解鎖。
  • 短信中心號碼:必須正確設定 AT+CSCA,否則發送失敗無錯誤碼。
  • SMSLib 版本:v3.5.0+ 支援 Java 8+,舊版 v2 API 完全不同,注意 Maven 坐標 org.smslib:smslib:3.5.0。
  • 並發發送:單 Modem 串行發送,高吞吐需多 Modem + Service.addGateway() 多 Gateway 輪詢。

現代化替代方案

  • HTTP SMS API:阿里云/騰訊雲/Twilio/Plivo 等雲通訊平台,REST API、無硬體維護、高併發、支援模板審核。
  • AT 指令直連:jSerialComm / PureJavaComm 直接發送 AT 指令,輕量無依賴,適合簡單場景。
  • Android Telephony:手機端 App 直接用 SmsManager 發送。

總結

SMSLib 提供企業級的 Modem 短信抽象層:Service 管理多 Gateway、SerialModemGateway 封裝 AT 指令、三大回調實現異步事件驅動。核心要點:**UCS2 編碼發送中文、正確配置串口/波特率/短信中心、啟用輪詢接收**。對於新專案,優先評估雲短信 API;若必須自建硬體,SMSLib 仍是 Java 生態最佳選擇。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved