SGIP(Short Message Gateway Interface Protocol)是中國聯通短信網關標準協議。本文基於華為 SGIP 開發包,完整示範下行發送、上行接收、狀態報告處理的 Java 實作要點。
SGIPSMProxy、SGIPSubmitMessage、SGIPDeliverMessage、Argspublic class MtSender {
// SP 配置(需向聯通申請)
private static final String SP_NUMBER = "**********"; // 接入號
private static final String CHARGE_NUMBER = "000000000000000000000"; // 計費號
private static final String CORP_ID = "*****"; // 企業代碼
private static final String LOGIN_NAME = "**"; // 登入名
private static final String LOGIN_PASS = "***"; // 登入密碼
private static final String HOST = "***.***.***.***"; // 網關 IP
private static final int PORT = ****; // 端口
public static void sendSms(String[] phones, String content) throws Exception {
Args args = new Args();
args.set("host", HOST);
args.set("port", PORT);
args.set("source-addr", parseNodeId("*******")); // 30000+CorpId 可能超 int
args.set("login-name", LOGIN_NAME);
args.set("login-pass", LOGIN_PASS);
args.set("transaction-timeout", 10);
args.set("read-timeout", 15);
SGIPSMProxy proxy = new SGIPSMProxy(args);
if (!proxy.connect(LOGIN_NAME, LOGIN_PASS)) {
throw new IllegalStateException("登入失敗");
}
SGIPSubmitMessage msg = new SGIPSubmitMessage(
SP_NUMBER, CHARGE_NUMBER, phones, CORP_ID, "", "03", "0", "0",
0, 0, "06", 0, null, null, 1, 0, 0, 15, 0,
content.getBytes("GB2312").length, content.getBytes("GB2312"), "0"
);
SGIPMessage resp = proxy.send(msg);
int status = processSubmitResp(resp);
if (status != 0) throw new RuntimeException("發送失敗:" + status);
}
private static int parseNodeId(String s) {
return new BigInteger(s).intValue(); // 處理 30000+CorpId 超 int 範圍
}
private static int processSubmitResp(SGIPMessage msg) {
SGIPSubmitRepMessage rep = (SGIPSubmitRepMessage) msg;
return rep.getResult(); // 0 成功
}
}
public class MoReceiver extends SGIPSMProxy {
private static final String SER_HOST = "***.***.***.***";
private static final int SER_PORT = ****;
private static final String LOCAL_HOST = "***.***.***.***";
private static final int LOCAL_PORT = ****;
public MoReceiver(Args args) {
super(args);
startService(LOCAL_HOST, LOCAL_PORT); // 本機監聽端口
}
@Override
public SGIPMessage onDeliver(SGIPDeliverMessage msg) {
processDeliver(msg);
return super.onDeliver(msg); // 返回響應
}
private void processDeliver(SGIPMessage msg) {
if (msg instanceof SGIPSubmitRepMessage) {
// 狀態報告
handleReport((SGIPSubmitRepMessage) msg);
} else if (msg instanceof SGIPDeliverMessage) {
// 上行短信
SGIPDeliverMessage mo = (SGIPDeliverMessage) msg;
String phone = mo.getUserNumber();
String content = mo.getMsgContent(); // 需按 GB2312 解碼
int cmdId = mo.getCommandId(); // 0: 普通上行
// 業務處理:存庫、推送、異步處理
processMoSms(phone, content);
}
}
private void handleReport(SGIPSubmitRepMessage rep) {
String msgId = rep.getMsgId();
int status = rep.getResult();
// 更新發送記錄狀態
}
}
| 難點 | 解決方案 |
|---|---|
| 源節點 ID 超 int 範圍 | BigInteger 解析後 intValue() |
| GB2312 編碼處理 | 發送 getBytes("GB2312"),接收 new String(bytes, "GB2312") |
| 長連接保活 | 定時發送 ActiveTest 心跳,處理斷線重連 |
| 併發發送控制 | 信號量/令牌桶限流,避免超過網關阈值 |
| 狀態報告匹配 | 建立 msgId → 發送記錄 映射,異步更新 |
| 優先級與費率 | 按業務類型設定 Priority、FeeType、FeeValue |
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 業務系統 │────▶│ 短信發送服務 │────▶│ SGIP 客戶端 │
└─────────────┘ │ (隊列/重試/ │ │ (連接池/心跳) │
│ 限流/監控) │ └──────┬──────┘
└──────────────┘ │
▲ ▼
┌────┴────┐ ┌─────────────┐
│ 狀態報告 │◀──────────│ 聯通 SMG │
│ 消費者 │ └─────────────┘
└─────────┘
SGIP 協議雖屬老牌標準,但在聯通短信業務中仍佔主導地位。掌握其協議細節、異常處理、生產級架構模式,是構建穩定短信服務的關鍵。