从具有 2 个线程的 gsm 调制解调器中选择短信
Picking sms from gsm modem with 2 threads
尝试执行一个应用程序,每隔一段时间从 gsm 调制解调器读取短信。
想到这个解决方案:
我的应用程序中有 2 个线程。
T1)- GSMModemHandler,它是串行通信的处理程序。
T2)- SMSPicker,每段时间请求短信并对其执行一些字符串算法。
我希望我的应用程序这样做:
A)- T2 使用 readAllMessages() 请求短信,这是 GSMModemHandler class 的一种方法,然后保持阻塞状态。
B)- T1 有一个 SerialEventListener,因此它会监听 GSM-Modem 发送的请求的响应,并将其发送回 T2。
C)- 一旦响应在来自 T2 class 的列表中可用,T2 恢复其有关字符串算法的任务,然后在等待一段时间后再次从 A 执行相同的操作。
我已经尝试编写代码,当我启动应用程序时,它会工作一段时间然后阻塞,我猜问题来自两个线程之间的误解,但找不到问题是以及如何解决它。
这是我的代码,结果是:
public class GSMModemHandler extends SerialPort implements
SerialPortEventListener{
private static final String
COMMAND_REMISE_A_ZERO = "ATZ",
COMMAND_SMS_MODE_TEXT = "AT+CMGF=1",
COMMAND_DETAILED_ERRORS = "AT+CMEE=1",
COMMAND_SET_UP_MEMORIES = "AT+CPMS=\"MT\",\"MT\",\"MT\"",
COMMAND_LIST_SUPPORTED_STORAGE_MODES = "AT+CPMS=?",
COMMAND_ENVOIE_SMS = "AT+CMGS=",
COMMAND_GET_ALL_SMS = "AT+CMGL=\"ALL\"",
COMMAND_GET_NEW_SMS = "AT+CMGL=\"REC UNREAD\"",
COMMAND_DELETE_ALL_MESSAGES = "AT+CMGD=0[,4]",
COMMAND_DELETE_READ_MESSAGES = "AT+CMGD=0[,1]";
private SMSPicker smsPicker = null;
private String response = "";
public GSMModemHandler(String port) throws SerialPortException{
super(port);
this.openPort();
this.setParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
this.addEventListener(this);
this.startGsm();
}
public void startGsm() throws SerialPortException{
this.writeString(GSMModemHandler.COMMAND_REMISE_A_ZERO + "\r\n");
this.writeString(GSMModemHandler.COMMAND_SMS_MODE_TEXT + "\r\n");
this.writeString(GSMModemHandler.COMMAND_DETAILED_ERRORS + "\r\n");
this.writeString(GSMModemHandler.COMMAND_SET_UP_MEMORIES + "\r\n");
}
public void sendMessage(SMS sms){
try{
if(this.isOpened()){
this.writeString(GSMModemHandler.COMMAND_ENVOIE_SMS + "\"" + sms.getCorrespondantSms() + "\"\r\n");
this.writeString(sms.getContenuSms() + '2');
}
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void readAllMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_GET_ALL_SMS + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void readUnreadMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_GET_NEW_SMS + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void deleteAllMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_DELETE_ALL_MESSAGES + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void deleteReadMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_DELETE_READ_MESSAGES + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public synchronized void fermerConnexion(){
try{
this.closePort();
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
AtomicBoolean nextResponseIsSms = new AtomicBoolean(false);
@Override
public void serialEvent(SerialPortEvent spe) {
try {
String reponse = this.readString();
System.out.println("GSM response = " + reponse);
// If the next response contains the wanted sms
if(reponse != null && reponse.contains("AT+CMGL=")){
this.nextResponseIsSms.set(true);
System.out.println("nextResponseIsSms = true");
}
// if the response contains sms
else if(this.nextResponseIsSms.get()){
this.smsPicker.getResponse().add(reponse);
System.out.println("response sent !");
this.deleteAllMessages(); // deleting the sms in the gsm modem
System.out.println("messages deleted");
this.nextResponseIsSms.set(false);
System.out.println("nextResponseIsSms = false");
// gives the SMSPicker the hand to treat the response
synchronized(this.smsPicker){ this.smsPicker.notify(); }
System.out.println("smsPicker notified");
}
} catch (SerialPortException ex) {
Logger.getLogger(GSMModemHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* @return the smsPicker
*/
public SMSPicker getSmsPicker() {
return smsPicker;
}
/**
* @param smsPicker the smsPicker to set
*/
public void setSmsPicker(SMSPicker smsPicker) {
this.smsPicker = smsPicker;
}
}
public class SMSPicker extends ControlledThread{
private GSMModemHandler modemGsm;
private SMSQueueToDatabase smsQueueHandler;
private volatile Queue<String> responses = new LinkedList<String>();
public SMSPicker(double frequency, GSMModemHandler gsmModem){
super(frequency);
this.modemGsm = gsmModem;
this.modemGsm.setSmsPicker(this);
this.smsQueueHandler = new SMSQueueToDatabase(frequency);
}
@Override
public void whatToDoBeforeTheLoop(){
this.smsQueueHandler.start();
try {
this.wait(2 * this.waitingPeriod.get());
} catch (InterruptedException ex) {
Logger.getLogger(SMSPicker.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void whatToDoDuringTheLoop() throws NullPointerException{
synchronized(this){
try {
System.out.println("I'm going to launch the request !");
// Sending the sms read request to the gsm modem
this.modemGsm.readAllMessages();
System.out.println("i'm going to be stopped!");
// wait till we get the answer
this.wait();
System.out.println("I've been stopped and now resuming");
}
catch (InterruptedException ex) {
Logger.getLogger(SMSPicker.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Treating the response in order to extract sms from it
while(!this.responses.isEmpty()){
String longMessage = this.responses.poll();
if(longMessage != null){
String[] shortMessages = null;
shortMessages = longMessage.split("\+CMGL: [0-9]*,\"");
if(shortMessages == null) continue;
for(String shortMessage: shortMessages){
int indexLastOK = shortMessage.lastIndexOf("OK");
if(indexLastOK != -1 && shortMessage.contains("+"))
this.smsQueueHandler.getSmsFifo().add(this.fromStringToSms(shortMessage
.substring(0,shortMessage.lastIndexOf("OK") - 2))); // if it is the last sms
else if(shortMessage.contains("REC")) // if it is not the last one
this.smsQueueHandler.getSmsFifo().add(this.fromStringToSms(shortMessage));
}
}
}
}
private SMS fromStringToSms(String stringSms){
String[] smsParts = stringSms.split(",");
String correspondantSms = smsParts[1].replaceAll("\"", "");
String dateSms = smsParts[3].replace("\"","").replaceAll("/", "-");
String heureSms = smsParts[4].substring(0,smsParts[4].lastIndexOf("\"")).substring(0, 8);
String contenuSms = stringSms.substring(stringSms.lastIndexOf("\"") + 3);
LocalDateTime momentSms = LocalDateTime.parse("20" + dateSms + "T" + heureSms);
return new SMS(correspondantSms,contenuSms,momentSms);
}
@Override
public void whatToDoAfterTheLoop() {
}
/**
* @return the modemGsm
*/
public GSMModemHandler getModemGsm() {
return modemGsm;
}
/**
* @param modemGsm the modemGsm to set
*/
public void setModemGsm(GSMModemHandler modemGsm) {
this.modemGsm = modemGsm;
}
/**
* @return the smsQueueHandler
*/
public SMSQueueToDatabase getSmsQueueHandler() {
return smsQueueHandler;
}
/**
* @param smsQueueHandler the smsQueueHandler to set
*/
public void setSmsQueueHandler(SMSQueueToDatabase smsQueueHandler) {
this.smsQueueHandler = smsQueueHandler;
}
/**
* @return the response
*/
public Queue<String> getResponse() {
return responses;
}
/**
* @param response the response to set
*/
public void setResponse(Queue<String> responses) {
this.responses = responses;
}
}
public abstract class ControlledThread extends Thread{
protected AtomicBoolean workable = null;
protected AtomicLong waitingPeriod = null;
public ControlledThread(double frequency){
super();
this.workable = new AtomicBoolean(true);
this.waitingPeriod = new AtomicLong(((long)(1000 / frequency)));
}
@Override
public synchronized void run() {
this.whatToDoBeforeTheLoop();
while(this.workable.get()){
try{
this.whatToDoDuringTheLoop();
this.wait(this.waitingPeriod.get());
}
catch(InterruptedException exp){
exp.printStackTrace();
}
}
this.whatToDoAfterTheLoop();
}
public void stopWorking(){
this.workable.set(false);
}
public synchronized boolean isWorking(){
return this.workable.get();
}
public abstract void whatToDoBeforeTheLoop();
public abstract void whatToDoDuringTheLoop();
public abstract void whatToDoAfterTheLoop();
}
结果:
注意:阻塞状态发生在红线处(BUILD STOPPED 只是我通过 kill 停止应用程序的结果)
提前致谢!
很可能,您遇到了错过的信号:您开始等待已经发生的 notify()
。
这是因为你开始无条件地等待。但是,您应该始终在检查其等待条件的循环中等待。
在您的情况下,继续等待的条件可能是直到提供答案为止。
所以 :
while (!hasAnswer()) {
this.wait();
}
您还必须确保您同步的监视器(在您的情况下为 SMSPicker
)正确保护确定条件的状态。由于您似乎只是公开了响应队列,所以它认为情况可能并非如此,但我遗漏了太多细节无法确定。
更详细的解释看here.
尝试执行一个应用程序,每隔一段时间从 gsm 调制解调器读取短信。
想到这个解决方案:
我的应用程序中有 2 个线程。
T1)- GSMModemHandler,它是串行通信的处理程序。 T2)- SMSPicker,每段时间请求短信并对其执行一些字符串算法。
我希望我的应用程序这样做:
A)- T2 使用 readAllMessages() 请求短信,这是 GSMModemHandler class 的一种方法,然后保持阻塞状态。
B)- T1 有一个 SerialEventListener,因此它会监听 GSM-Modem 发送的请求的响应,并将其发送回 T2。
C)- 一旦响应在来自 T2 class 的列表中可用,T2 恢复其有关字符串算法的任务,然后在等待一段时间后再次从 A 执行相同的操作。
我已经尝试编写代码,当我启动应用程序时,它会工作一段时间然后阻塞,我猜问题来自两个线程之间的误解,但找不到问题是以及如何解决它。
这是我的代码,结果是:
public class GSMModemHandler extends SerialPort implements
SerialPortEventListener{
private static final String
COMMAND_REMISE_A_ZERO = "ATZ",
COMMAND_SMS_MODE_TEXT = "AT+CMGF=1",
COMMAND_DETAILED_ERRORS = "AT+CMEE=1",
COMMAND_SET_UP_MEMORIES = "AT+CPMS=\"MT\",\"MT\",\"MT\"",
COMMAND_LIST_SUPPORTED_STORAGE_MODES = "AT+CPMS=?",
COMMAND_ENVOIE_SMS = "AT+CMGS=",
COMMAND_GET_ALL_SMS = "AT+CMGL=\"ALL\"",
COMMAND_GET_NEW_SMS = "AT+CMGL=\"REC UNREAD\"",
COMMAND_DELETE_ALL_MESSAGES = "AT+CMGD=0[,4]",
COMMAND_DELETE_READ_MESSAGES = "AT+CMGD=0[,1]";
private SMSPicker smsPicker = null;
private String response = "";
public GSMModemHandler(String port) throws SerialPortException{
super(port);
this.openPort();
this.setParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
this.addEventListener(this);
this.startGsm();
}
public void startGsm() throws SerialPortException{
this.writeString(GSMModemHandler.COMMAND_REMISE_A_ZERO + "\r\n");
this.writeString(GSMModemHandler.COMMAND_SMS_MODE_TEXT + "\r\n");
this.writeString(GSMModemHandler.COMMAND_DETAILED_ERRORS + "\r\n");
this.writeString(GSMModemHandler.COMMAND_SET_UP_MEMORIES + "\r\n");
}
public void sendMessage(SMS sms){
try{
if(this.isOpened()){
this.writeString(GSMModemHandler.COMMAND_ENVOIE_SMS + "\"" + sms.getCorrespondantSms() + "\"\r\n");
this.writeString(sms.getContenuSms() + '2');
}
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void readAllMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_GET_ALL_SMS + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void readUnreadMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_GET_NEW_SMS + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void deleteAllMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_DELETE_ALL_MESSAGES + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public void deleteReadMessages(){
try{
if(this.isOpened())
this.writeString(GSMModemHandler.COMMAND_DELETE_READ_MESSAGES + "\r\n");
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
public synchronized void fermerConnexion(){
try{
this.closePort();
}
catch(SerialPortException exp){
exp.printStackTrace();
}
}
AtomicBoolean nextResponseIsSms = new AtomicBoolean(false);
@Override
public void serialEvent(SerialPortEvent spe) {
try {
String reponse = this.readString();
System.out.println("GSM response = " + reponse);
// If the next response contains the wanted sms
if(reponse != null && reponse.contains("AT+CMGL=")){
this.nextResponseIsSms.set(true);
System.out.println("nextResponseIsSms = true");
}
// if the response contains sms
else if(this.nextResponseIsSms.get()){
this.smsPicker.getResponse().add(reponse);
System.out.println("response sent !");
this.deleteAllMessages(); // deleting the sms in the gsm modem
System.out.println("messages deleted");
this.nextResponseIsSms.set(false);
System.out.println("nextResponseIsSms = false");
// gives the SMSPicker the hand to treat the response
synchronized(this.smsPicker){ this.smsPicker.notify(); }
System.out.println("smsPicker notified");
}
} catch (SerialPortException ex) {
Logger.getLogger(GSMModemHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* @return the smsPicker
*/
public SMSPicker getSmsPicker() {
return smsPicker;
}
/**
* @param smsPicker the smsPicker to set
*/
public void setSmsPicker(SMSPicker smsPicker) {
this.smsPicker = smsPicker;
}
}
public class SMSPicker extends ControlledThread{
private GSMModemHandler modemGsm;
private SMSQueueToDatabase smsQueueHandler;
private volatile Queue<String> responses = new LinkedList<String>();
public SMSPicker(double frequency, GSMModemHandler gsmModem){
super(frequency);
this.modemGsm = gsmModem;
this.modemGsm.setSmsPicker(this);
this.smsQueueHandler = new SMSQueueToDatabase(frequency);
}
@Override
public void whatToDoBeforeTheLoop(){
this.smsQueueHandler.start();
try {
this.wait(2 * this.waitingPeriod.get());
} catch (InterruptedException ex) {
Logger.getLogger(SMSPicker.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void whatToDoDuringTheLoop() throws NullPointerException{
synchronized(this){
try {
System.out.println("I'm going to launch the request !");
// Sending the sms read request to the gsm modem
this.modemGsm.readAllMessages();
System.out.println("i'm going to be stopped!");
// wait till we get the answer
this.wait();
System.out.println("I've been stopped and now resuming");
}
catch (InterruptedException ex) {
Logger.getLogger(SMSPicker.class.getName()).log(Level.SEVERE, null, ex);
}
}
// Treating the response in order to extract sms from it
while(!this.responses.isEmpty()){
String longMessage = this.responses.poll();
if(longMessage != null){
String[] shortMessages = null;
shortMessages = longMessage.split("\+CMGL: [0-9]*,\"");
if(shortMessages == null) continue;
for(String shortMessage: shortMessages){
int indexLastOK = shortMessage.lastIndexOf("OK");
if(indexLastOK != -1 && shortMessage.contains("+"))
this.smsQueueHandler.getSmsFifo().add(this.fromStringToSms(shortMessage
.substring(0,shortMessage.lastIndexOf("OK") - 2))); // if it is the last sms
else if(shortMessage.contains("REC")) // if it is not the last one
this.smsQueueHandler.getSmsFifo().add(this.fromStringToSms(shortMessage));
}
}
}
}
private SMS fromStringToSms(String stringSms){
String[] smsParts = stringSms.split(",");
String correspondantSms = smsParts[1].replaceAll("\"", "");
String dateSms = smsParts[3].replace("\"","").replaceAll("/", "-");
String heureSms = smsParts[4].substring(0,smsParts[4].lastIndexOf("\"")).substring(0, 8);
String contenuSms = stringSms.substring(stringSms.lastIndexOf("\"") + 3);
LocalDateTime momentSms = LocalDateTime.parse("20" + dateSms + "T" + heureSms);
return new SMS(correspondantSms,contenuSms,momentSms);
}
@Override
public void whatToDoAfterTheLoop() {
}
/**
* @return the modemGsm
*/
public GSMModemHandler getModemGsm() {
return modemGsm;
}
/**
* @param modemGsm the modemGsm to set
*/
public void setModemGsm(GSMModemHandler modemGsm) {
this.modemGsm = modemGsm;
}
/**
* @return the smsQueueHandler
*/
public SMSQueueToDatabase getSmsQueueHandler() {
return smsQueueHandler;
}
/**
* @param smsQueueHandler the smsQueueHandler to set
*/
public void setSmsQueueHandler(SMSQueueToDatabase smsQueueHandler) {
this.smsQueueHandler = smsQueueHandler;
}
/**
* @return the response
*/
public Queue<String> getResponse() {
return responses;
}
/**
* @param response the response to set
*/
public void setResponse(Queue<String> responses) {
this.responses = responses;
}
}
public abstract class ControlledThread extends Thread{
protected AtomicBoolean workable = null;
protected AtomicLong waitingPeriod = null;
public ControlledThread(double frequency){
super();
this.workable = new AtomicBoolean(true);
this.waitingPeriod = new AtomicLong(((long)(1000 / frequency)));
}
@Override
public synchronized void run() {
this.whatToDoBeforeTheLoop();
while(this.workable.get()){
try{
this.whatToDoDuringTheLoop();
this.wait(this.waitingPeriod.get());
}
catch(InterruptedException exp){
exp.printStackTrace();
}
}
this.whatToDoAfterTheLoop();
}
public void stopWorking(){
this.workable.set(false);
}
public synchronized boolean isWorking(){
return this.workable.get();
}
public abstract void whatToDoBeforeTheLoop();
public abstract void whatToDoDuringTheLoop();
public abstract void whatToDoAfterTheLoop();
}
结果:
注意:阻塞状态发生在红线处(BUILD STOPPED 只是我通过 kill 停止应用程序的结果)
提前致谢!
很可能,您遇到了错过的信号:您开始等待已经发生的 notify()
。
这是因为你开始无条件地等待。但是,您应该始终在检查其等待条件的循环中等待。
在您的情况下,继续等待的条件可能是直到提供答案为止。
所以 :
while (!hasAnswer()) {
this.wait();
}
您还必须确保您同步的监视器(在您的情况下为 SMSPicker
)正确保护确定条件的状态。由于您似乎只是公开了响应队列,所以它认为情况可能并非如此,但我遗漏了太多细节无法确定。
更详细的解释看here.