首页 > 解决方案 > 当我得到 gsm 调制解调器时如何实现重试机制异常:没有从手机收到数据?

问题描述

public class GSMModemConnection { 我为接收 SMS 创建了一个 Windows 服务,我使用的是 Wavecom Gsm 调制解调器 1306B。但过了一会儿,我得到了一个例外:没有从手机收到数据。我在 StackOverflow 中搜索过我发现这个链接异常:没有从手机收到数据

有人指出要创建一个重试机制,但我不知道如何实现它。

static void Main(string[] args)
{
    GSMModemConnection gsm = new GSMModemConnection();
    var result = gsm.OpenPort();
    Console.WriteLine(result.PortName);


    while (true)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        ShortMessage execResult = gsm.ReadSMS(result, "AT+CMGL=\"ALL\"");
        Console.WriteLine(execResult.Message);
        Console.WriteLine(execResult.Status);

    }

}

   public class GSMModemConnection
    {
        public AutoResetEvent receiveNow;
        //string strPortName, string strBaudRate
        public SerialPort OpenPort()
        {
            receiveNow = new AutoResetEvent(false);
            SerialPort port = new SerialPort();
            port.PortName = "COM3";
            port.BaudRate = 115200 /*Convert.ToInt32(strBaudRate)*/;               //updated by Anila (9600)
            port.DataBits = 8;
            port.StopBits = StopBits.One;
            port.Parity = Parity.None;
            port.ReadTimeout = 300;
            port.WriteTimeout = 300;
            port.Encoding = Encoding.GetEncoding("iso-8859-1");
            port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
            port.Open();
            port.DtrEnable = true;
            port.RtsEnable = true;
            return port;
        }

        //Close Port
        public void ClosePort(SerialPort port)
        {
            port.Close();
            port.DataReceived -= new SerialDataReceivedEventHandler(port_DataReceived);
            port = null;
        }

        //Execute AT Command
        public string ExecCommand(SerialPort port, string command, int responseTimeout, string errorMessage)
        {

            try
            {
                //receiveNow = new AutoResetEvent();
                port.DiscardOutBuffer();
                port.DiscardInBuffer();
                receiveNow.Reset();
                port.Write(command + "\r");

                //Thread.Sleep(3000); //3 seconds
                string input = ReadResponse(port, responseTimeout);
                if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
                    throw new ApplicationException("No success message was received.");
                return input;
            }
            catch (Exception ex)
            {
                throw new ApplicationException(errorMessage, ex);
            }
        }

        //Receive data from port
        public void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (e.EventType == SerialData.Chars)
                receiveNow.Set();
        }
        public string ReadResponse(SerialPort port, int timeout)
        {
            string buffer = string.Empty;
            do
            {
                if (receiveNow.WaitOne(timeout, false))
                {
                    string t = port.ReadExisting();
                    buffer += t;
                }
                else
                {
                    if (buffer.Length > 0)
                        throw new ApplicationException("Response received is incomplete.");
                    else
                        throw new ApplicationException("No data received from phone.");
                }
            }
            while (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"));
            return buffer;
        }

        public ShortMessage ReadSMS(SerialPort port, string p_strCommand)
        {

            // Set up the phone and read the messages
            ShortMessage messages = null;
            try
            {

                #region Execute Command
                // Check connection
                var a = ExecCommand(port, "AT", 300, "No phone connected");
                // Use message format "Text mode"
                var b = ExecCommand(port, "AT+CMGF=1\r", 300, "Failed to set message format.");
                // Use character set "PCCP437"
                //var c = ExecCommand(port, "AT+CSCS=\"PCCP437\"", 300, "Failed to set character set.");
                // Select SIM storage
                //var d = ExecCommand(port, "AT+CPMS=\"SM\"", 300, "Failed to select message storage.");
                // Read the messages
                string input = ExecCommand(port, p_strCommand, 5000, "Failed to read the messages.");
                #endregion

                #region Parse messages
                messages = ParseMessages(input);
                #endregion

            }
            catch (Exception ex)
            {
                throw ex;
            }

            if (messages != null)
                return messages;
            else
                return null;

        }
        public ShortMessage ParseMessages(string input)
        {
            ShortMessage msg = new ShortMessage();

            //ShortMessageCollection messages = new ShortMessageCollection();
            try
            {
                Regex r = new Regex(@"\+CMGL: (\d+),""(.+)"",""(.+)"",(.*),""(.+)""\r\n(.+)\r\n");
                Match m = r.Match(input);
                while (m.Success)
                {
                    //msg.Index = int.Parse(m.Groups[1].Value);
                    msg.Index = int.Parse(m.Groups[1].Value);
                    msg.Status = m.Groups[2].Value;
                    msg.Sender = m.Groups[3].Value;
                    msg.Alphabet = m.Groups[4].Value;
                    msg.Sent = m.Groups[5].Value;
                    msg.Message = m.Groups[6].Value;
                    //messages.Add(msg);

                    m = m.NextMatch();
                }

            }
            catch (Exception ex)
            {
                throw ex;
            }
            return msg;
        }

    }

标签: c#windows-servicesgsm

解决方案


您确实有一个重试机制,其中包含来自以下表达式的 DO-WHILE 循环:

public string ReadResponse(SerialPort port, int timeout)
    {
        string buffer = string.Empty;
        do
        {
            if (receiveNow.WaitOne(timeout, false))
            {
                string t = port.ReadExisting();
                buffer += t;
            }
            else
            {
                if (buffer.Length > 0)
                    throw new ApplicationException("Response received is incomplete.");
                else
                    throw new ApplicationException("No data received from phone.");
            }
        }
        while (!buffer.EndsWith("\r\nOK\r\n") && !buffer.EndsWith("\r\n> ") && !buffer.EndsWith("\r\nERROR\r\n"));
        return buffer;
    }

你可以做的是减少错误报告机制的粒度。例如,在这种情况下,该行将throw new ApplicationException()中断循环并在 Exec() 函数中被捕获,然后再次抛出。如果您只想等待循环关闭并执行 DO-WHILE 循环,我将替换以下代码部分:

else
            {
                if (buffer.Length > 0)
                    throw new ApplicationException("Response received is incomplete.");
                else
                    throw new ApplicationException("No data received from phone.");
            }

和:

else
            {
                if (buffer.Length > 0)
                    bufferError += "Response received is incomplete.\n";
                else
                    bufferError += "No data received from phone.\n";
            }

为什么?在 DO-WHILE 循环之后,缓冲区将返回 string.Empty 或某个值。在代码中,您有:

 string input = ReadResponse(port, responseTimeout);
            if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
                throw new ApplicationException("No success message was received.");
            return input;

基本上,如果返回的缓冲区是 string.Empty,则会再次抛出异常。

通过返回缓冲区错误,您可以稍后决定如何处理它,但 DO-WHILE 循环将至少运行一次,直到满足 WHILE 表达式的条件。其余代码应如下所示:

//Thread.Sleep(3000); //3 seconds
            string bufferErrors = string.Empty;
            string input = ReadResponse(port, responseTimeout, bufferErrors);
            if ((input.Length == 0) || ((!input.EndsWith("\r\n> ")) && (!input.EndsWith("\r\nOK\r\n"))))
                throw new ApplicationException("No success message was received.");
            if (!string.IsNullOrWhiteSpace(bufferErrors))
            {
                //Handle bufferErrors
            }
            return input;

记得在 ReadResponse 中声明 out 参数

public string ReadResponse(SerialPort port, int timeout, out string bufferError)
    {
        string buffer = string.Empty;
        bufferError = string.Empty;

推荐阅读