314
技術社區[雲棲]
SMSLib開發指南
一、SMSLib簡介
SMSLib是一個開放源代碼的短信貓二次開發包,有JAVA和.Net兩個版本,目前最新版為v3.5.2。
圖1-1
二、Window平台
1、在smslib官網下載“SMSLib for Java v3.5.2”開發包,並解壓,目錄結構如下圖所示:
圖2-1
圖2-2
lib:存放二次開發包(smslib-3.5.2.jar)和運行時的依賴包(slf4j、log4j、commons-net、jsmpp等)(重要)
dist:存放短信貓服務開發包(smsserver-3.5.2.jar),該包包括了smslib-3.5.2.jar中的所有核心類。如果是將短信貓作為服務的方式部署,不需要額外寫代碼開發短信發送和接收的接口,直接部署短信服務即可,詳細的步聚,可以參考《短信貓服務安裝與配置指南》。(重要)
doc:smslib介紹、使用指南、smsserver安裝與配置等文檔(重要)
javadoc:二次開發包API
src:存放二次開發包源碼和示例源碼
misc:smslib日誌(log4j)配置配置模板、smsserver數據庫建庫腳本及服務接口等文件
build:項目管理相關文件(不重要)
2、下載SUN JavaComm v2 (Win32)動態庫,並解壓,目錄結構如下圖所示:
圖3-1
3、運行環境配置
- 複製“圖3-1”中javax.comm.properties文件到%JAVA_HOME%\jre\lib目錄下,win32com.dll文件到%JAVA_HOME%\jre\bin目錄下
- 複製“圖3-1”中comm.jar和圖2-2中所有jar文件到CLASSPATH目錄下(如果是用eclipse等IDE工具,將這些jar包導入到工程中
// SendMessage.java - Sample application. // 短信發送測試程序 // This application shows you the basic procedure for sending messages. // You will find how to send synchronous and asynchronous messages. // // For asynchronous dispatch, the example application sets a callback // notification, to see what's happened with messages. package examples.modem; import org.smslib.AGateway; import org.smslib.IOutboundMessageNotification; import org.smslib.Library; import org.smslib.OutboundMessage; import org.smslib.Service; import org.smslib.modem.SerialModemGateway; public class SendMessage { public void doIt() throws Exception { OutboundNotification outboundNotification = new OutboundNotification(); System.out.println("Example: Send message from a serial gsm modem."); System.out.println(Library.getLibraryDescription()); System.out.println("Version: " + Library.getLibraryVersion()); /* modem.com1:網關ID(即短信貓端口編號) COM4:串口名稱(在window中以COMXX表示端口名稱,在linux,unix平台下以ttyS0-N或ttyUSB0-N表示端口名稱),通過端口檢測程序得到可用的端口 115200:串口每秒發送數據的bit位數,必須設置正確才可以正常發送短信,可通過程序進行檢測。常用的有115200、9600 Huawei:短信貓生產廠商,不同的短信貓生產廠商smslib所封裝的AT指令接口會不一致,必須設置正確.常見的有Huawei、wavecom等廠商 最後一個參數表示設備的型號,可選 */ SerialModemGateway gateway = new SerialModemGateway("modem.com1", "COM4", 115200, "Huawei", ""); gateway.setInbound(true); //設置true,表示該網關可以接收短信,根據需求修改 gateway.setOutbound(true);//設置true,表示該網關可以發送短信,根據需求修改 gateway.setSimPin("0000");//sim卡鎖,一般默認為0000或1234 // Explicit SMSC address set is required for some modems. // Below is for VODAFONE GREECE - be sure to set your own! gateway.setSmscNumber("+306942190000");//短信服務中心號碼 Service.getInstance().setOutboundMessageNotification(outboundNotification); //發送短信成功後的回調函方法 Service.getInstance().addGateway(gateway); //將網關添加到短信貓服務中 Service.getInstance().startService(); //啟動服務,進入短信發送就緒狀態 System.out.println(); //打印設備信息 System.out.println("Modem Information:"); System.out.println(" Manufacturer: " + gateway.getManufacturer()); System.out.println(" Model: " + gateway.getModel()); System.out.println(" Serial No: " + gateway.getSerialNo()); System.out.println(" SIM IMSI: " + gateway.getImsi()); System.out.println(" Signal Level: " + gateway.getSignalLevel() + " dBm"); System.out.println(" Battery Level: " + gateway.getBatteryLevel() + "%"); System.out.println(); // Send a message synchronously. OutboundMessage msg = new OutboundMessage("306974000000", "Hello from SMSLib!"); //參數1:手機號碼 參數2:短信內容 Service.getInstance().sendMessage(msg); //執行發送短信 System.out.println(msg); // Or, send out a WAP SI message. //OutboundWapSIMessage wapMsg = new OutboundWapSIMessage("306974000000", //new URL("https://www.smslib.org/"), "Visit SMSLib now!"); //Service.getInstance().sendMessage(wapMsg); //System.out.println(wapMsg); // You can also queue some asynchronous messages to see how the callbacks // are called... //msg = new OutboundMessage("309999999999", "Wrong number!"); //srv.queueMessage(msg, gateway.getGatewayId()); //msg = new OutboundMessage("308888888888", "Wrong number!"); //srv.queueMessage(msg, gateway.getGatewayId()); System.out.println("Now Sleeping - Hit <enter> to terminate."); System.in.read(); Service.getInstance().stopService(); } /* 短信發送成功後,調用該接口。並將發送短信的網關和短信內容對象傳給process接口 */ public class OutboundNotification implements IOutboundMessageNotification { public void process(AGateway gateway, OutboundMessage msg) { System.out.println("Outbound handler called from Gateway: " + gateway.getGatewayId()); System.out.println(msg); } } public static void main(String args[]) { SendMessage app = new SendMessage(); try { app.doIt(); } catch (Exception e) { e.printStackTrace(); } } }
// ReadMessages.java - Sample application. // 短信讀取程序 // This application shows you the basic procedure needed for reading // SMS messages from your GSM modem, in synchronous mode. // // Operation description: // The application setup the necessary objects and connects to the phone. // As a first step, it reads all messages found in the phone. // Then, it goes to sleep, allowing the asynchronous callback handlers to // be called. Furthermore, for callback demonstration purposes, it responds // to each received message with a "Got It!" reply. // // Tasks: // 1) Setup Service object. // 2) Setup one or more Gateway objects. // 3) Attach Gateway objects to Service object. // 4) Setup callback notifications. // 5) Run package examples.modem; import java.util.ArrayList; import java.util.List; import javax.crypto.spec.SecretKeySpec; import org.smslib.AGateway; import org.smslib.AGateway.GatewayStatuses; import org.smslib.AGateway.Protocols; import org.smslib.ICallNotification; import org.smslib.IGatewayStatusNotification; import org.smslib.IInboundMessageNotification; import org.smslib.IOrphanedMessageNotification; import org.smslib.InboundMessage; import org.smslib.InboundMessage.MessageClasses; import org.smslib.Library; import org.smslib.Message.MessageTypes; import org.smslib.Service; import org.smslib.crypto.AESKey; import org.smslib.modem.SerialModemGateway; public class ReadMessages { public void doIt() throws Exception { // Define a list which will hold the read messages. List<InboundMessage> msgList; // Create the notification callback method for inbound & status report // messages. InboundNotification inboundNotification = new InboundNotification(); // Create the notification callback method for inbound voice calls. CallNotification callNotification = new CallNotification(); //Create the notification callback method for gateway statuses. GatewayStatusNotification statusNotification = new GatewayStatusNotification(); OrphanedMessageNotification orphanedMessageNotification = new OrphanedMessageNotification(); try { System.out.println("Example: Read messages from a serial gsm modem."); System.out.println(Library.getLibraryDescription()); System.out.println("Version: " + Library.getLibraryVersion()); // Create the Gateway representing the serial GSM modem. SerialModemGateway gateway = new SerialModemGateway("modem.com4", "COM4", 115200, "Huawei", "E160"); // Set the modem protocol to PDU (alternative is TEXT). PDU is the default, anyway... gateway.setProtocol(Protocols.PDU); // Do we want the Gateway to be used for Inbound messages? gateway.setInbound(true); // Do we want the Gateway to be used for Outbound messages? gateway.setOutbound(true); // Let SMSLib know which is the SIM PIN. gateway.setSimPin("0000"); // Set up the notification methods. Service.getInstance().setInboundMessageNotification(inboundNotification); Service.getInstance().setCallNotification(callNotification); Service.getInstance().setGatewayStatusNotification(statusNotification); Service.getInstance().setOrphanedMessageNotification(orphanedMessageNotification); // Add the Gateway to the Service object. Service.getInstance().addGateway(gateway); // Similarly, you may define as many Gateway objects, representing // various GSM modems, add them in the Service object and control all of them. // Start! (i.e. connect to all defined Gateways) Service.getInstance().startService(); // Printout some general information about the modem. System.out.println(); System.out.println("Modem Information:"); System.out.println(" Manufacturer: " + gateway.getManufacturer()); System.out.println(" Model: " + gateway.getModel()); System.out.println(" Serial No: " + gateway.getSerialNo()); System.out.println(" SIM IMSI: " + gateway.getImsi()); System.out.println(" Signal Level: " + gateway.getSignalLevel() + " dBm"); System.out.println(" Battery Level: " + gateway.getBatteryLevel() + "%"); System.out.println(); // In case you work with encrypted messages, its a good time to declare your keys. // Create a new AES Key with a known key value. // Register it in KeyManager in order to keep it active. SMSLib will then automatically // encrypt / decrypt all messages send to / received from this number. Service.getInstance().getKeyManager().registerKey("+306948494037", new AESKey(new SecretKeySpec("0011223344556677".getBytes(), "AES"))); // Read Messages. The reading is done via the Service object and // affects all Gateway objects defined. This can also be more directed to a specific // Gateway - look the JavaDocs for information on the Service method calls. msgList = new ArrayList<InboundMessage>(); Service.getInstance().readMessages(msgList, MessageClasses.ALL); for (InboundMessage msg : msgList) System.out.println(msg); // Sleep now. Emulate real world situation and give a chance to the notifications // methods to be called in the event of message or voice call reception. System.out.println("Now Sleeping - Hit <enter> to stop service."); System.in.read(); System.in.read(); } catch (Exception e) { e.printStackTrace(); } finally { Service.getInstance().stopService(); } } public class InboundNotification implements IInboundMessageNotification { public void process(AGateway gateway, MessageTypes msgType, InboundMessage msg) { if (msgType == MessageTypes.INBOUND) System.out.println(">>> New Inbound message detected from Gateway: " + gateway.getGatewayId()); else if (msgType == MessageTypes.STATUSREPORT) System.out.println(">>> New Inbound Status " + "Report message detected from Gateway: " + gateway.getGatewayId()); System.out.println(msg); } } public class CallNotification implements ICallNotification { public void process(AGateway gateway, String callerId) { System.out.println(">>> New call detected from Gateway: " + gateway.getGatewayId() + " : " + callerId); } } public class GatewayStatusNotification implements IGatewayStatusNotification { public void process(AGateway gateway, GatewayStatuses oldStatus, GatewayStatuses newStatus) { System.out.println(">>> Gateway Status change for " + gateway.getGatewayId() + ", OLD: " + oldStatus + " -> NEW: " + newStatus); } } public class OrphanedMessageNotification implements IOrphanedMessageNotification { public boolean process(AGateway gateway, InboundMessage msg) { System.out.println(">>> Orphaned message part detected from " + gateway.getGatewayId()); System.out.println(msg); // Since we are just testing, return FALSE and keep the orphaned message part. return false; } } public static void main(String args[]) { ReadMessages app = new ReadMessages(); try { app.doIt(); } catch (Exception e) { e.printStackTrace(); } } }
三、Linux、Unix、Solaris平台

- 複製圖4-1中Linux目錄下的librxtxSerial.so文件至$JAVA_HOME/jre/lib/$(ARCH)/目錄下,複製RXTXcomm.jar到應用程序的CLASSPATH或$JAVA_HOME/jre/lib/ext目錄下
- 複製圖3-1中的javax.comm.properties文件至$JAVA_HOME/jre/lib目錄下,並將文件中的Driver=com.sun.comm.Win32Driver改成Driver=gnu.io.CommDriver。文件內容如下圖所示:
import gnu.io.*; import java.util.*; import java.io.*; public class CommTest { static CommPortIdentifier portId; static Enumeration portList; static int bauds[] = { 9600, 19200, 57600, 115200 }; //檢測端口所支持的波特率 public static void main(String[] args) { portList = CommPortIdentifier.getPortIdentifiers(); System.out.println("短信設備端口連接測試..."); while (portList.hasMoreElements()) { portId = (CommPortIdentifier) portList.nextElement(); if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { 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; String response; serialPort = (SerialPort) portId.open("SMSLibCommTester", 1971); 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) { } response = ""; c = inStream.read(); while (c != -1) { response += (char) c; c = inStream.read(); } if (response.indexOf("OK") >= 0) { try { System.out.print(" 獲取設備信息..."); outStream.write('A'); outStream.write('T'); outStream.write('+'); outStream.write('C'); outStream.write('G'); outStream.write('M'); outStream.write('M'); outStream.write('\r'); response = ""; c = inStream.read(); while (c != -1) { response += (char) c; c = inStream.read(); } System.out.println(" 發現設備: " + response.replaceAll("\\s+OK\\s+", "").replaceAll("\n", "").replaceAll("\r", "")); } catch (Exception e) { System.out.println(" 沒有發現設備!"); } } else System.out.println(" 沒有發現設備!"); serialPort.close(); } catch (Exception e) { System.out.println(" 沒有發現設備!"); } } } } } }
注意事項:
1、使用smslib庫之前,如果你的設備是usb數據線,先檢查係統中該設備驅動程序是否已安裝,在window環境下,廠商一般會提供設備的驅動程序,在linux環境下,內核2.6.32或以上版本,預裝了常用設備的USB轉串口驅動,如果係統未自動識別該設備,就需要自行安裝該設備的驅動程序了。
2、在開發過程中,org.smslib.TimeoutException: No response from device是最常遇到的一個異常,解決方案請參考:短信貓JAVA二次開發包SMSLib,org.smslib.TimeoutException: No response from device解決方案
最後更新:2017-04-02 17:28:38