短信从C#连接到手机并获得响应

我写了代码发送短信使用我的GSM电话,通过COM端口连接到计算机。 代码如下。

问题是,我确实看到它在电话的发件箱中,而且它实际上似乎已经发送,但是当我联系收件人时,他们说我还没有收到邮件。

我testing手机,并创build和发送消息,只使用手机,它完美的作品。 但是,当我用我的代码这样做,它已经发送,我从手机得到所有正确的AT COMMAND响应,但实际上不发送消息。

这里是代码:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading; using System.IO.Ports; namespace WindowsFormsApplication1 { public partial class Form1 : Form { SerialPort serialPort1; int m_iTxtMsgState = 0; const int NUM_MESSAGE_STATES = 4; const string RESERVED_COM_1 = "COM1"; const string RESERVED_COM_4 = "COM4"; public Form1() { InitializeComponent(); this.Closing += new CancelEventHandler(Form1_Closing); } private void Form1_Load(object sender, EventArgs e) { serialPort1 = new SerialPort(GetUSBComPort()); if (serialPort1.IsOpen) { serialPort1.Close(); } serialPort1.Open(); //ThreadStart myThreadDelegate = new ThreadStart(ReceiveAndOutput); //Thread myThread = new Thread(myThreadDelegate); //myThread.Start(); this.serialPort1.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived); } private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e) { serialPort1.Close(); } private void SendLine(string sLine) { serialPort1.Write(sLine); sLine = sLine.Replace("\u001A", ""); consoleOut.Text += sLine; } public void DoWork() { ProcessMessageState(); } public void ProcessMessageState() { switch (m_iTxtMsgState) { case 0: m_iTxtMsgState = 1; SendLine("AT\r\n"); //NOTE: SendLine must be the last thing called in all of these! break; case 1: m_iTxtMsgState = 2; SendLine("AT+CMGF=1\r\n"); break; case 2: m_iTxtMsgState = 3; SendLine("AT+CMGW=" + Convert.ToChar(34) + "+9737387467" + Convert.ToChar(34) + "\r\n"); break; case 3: m_iTxtMsgState = 4; SendLine("A simple demo of SMS text messaging." + Convert.ToChar(26)); break; case 4: m_iTxtMsgState = 5; break; case 5: m_iTxtMsgState = NUM_MESSAGE_STATES; break; } } private string GetStoredSMSID() { return null; } /* //I don't think this part does anything private void serialPort1_DataReceived_1(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { string response = serialPort1.ReadLine(); this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n"))); } */ void sp_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { Thread.Sleep(500); char[] msg; msg = new char[613]; int iNumToRead = serialPort1.BytesToRead; serialPort1.Read(msg, 0, iNumToRead); string response = new string(msg); this.BeginInvoke(new MethodInvoker(() => textBox1.AppendText(response + "\r\n"))); serialPort1.DiscardInBuffer(); if (m_iTxtMsgState == 4) { int pos_cmgw = response.IndexOf("+CMGW:"); string cmgw_num = response.Substring(pos_cmgw + 7, 4); SendLine("AT+CMSS=" + cmgw_num + "\r\n"); //stop listening to messages received } if (m_iTxtMsgState < NUM_MESSAGE_STATES) { ProcessMessageState(); } } catch { } } private void button1_Click(object sender, EventArgs e) { m_iTxtMsgState = 0; DoWork(); } private void button2_Click(object sender, EventArgs e) { string[] sPorts = SerialPort.GetPortNames(); foreach (string port in sPorts) { consoleOut.Text += port + "\r\n"; } } private string GetUSBComPort() { string[] sPorts = SerialPort.GetPortNames(); foreach (string port in sPorts) { if (port != RESERVED_COM_1 && port != RESERVED_COM_4) { return port; } } return null; } } 

这是我的代码与U9 Telia蜂窝调制解调器一起工作(testing):

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Diagnostics; using System.Configuration; using UsbEject.Library; using Utils; namespace Hardware { public class TeliaModem : IDisposable { public delegate void NewSmsHandler(InboundSMS sms); public event NewSmsHandler OnNewSMS; #region private data System.IO.Ports.SerialPort modemPort; Timeouter _lastModemKeepAlive; private delegate void DataReceivedDelegate(); private DataReceivedDelegate dataReceivedDelegate; Queue<OutboundSMS> _outSmses = new Queue<OutboundSMS>(); enum ModemState { Error = -1, NotInitialized, PowerUp, Initializing, Idle, SendingSMS, KeepAliveAwaitingResponse }; Timeouter ModemStateTimeouter = new Timeouter(timeout_s: 10, autoReset: false); ModemState _modemState = ModemState.NotInitialized; ModemState CurrentModemState { get { return _modemState; } set { _modemState = value; ModemStateTimeouter.Reset(); NihLog.Write(NihLog.Level.Debug, "State changed to: " + value.ToString()); } } private System.Windows.Forms.Control _mainThreadOwnder; #endregion public TeliaModem(System.Windows.Forms.Control mainThreadOwnder) { _mainThreadOwnder = mainThreadOwnder; dataReceivedDelegate = new DataReceivedDelegate(OnDataReceived); } public void SendSMS(string phone, string text) { _outSmses.Enqueue(new OutboundSMS(phone, text)); HeartBeat(); } private void SendSmsNow() { OutboundSMS sms = _outSmses.Peek(); sms.Attempt++; if (sms.Attempt > sms.MaxTries) { NihLog.Write(NihLog.Level.Error, "Failure to send after " + sms.MaxTries + " tries"); _outSmses.Dequeue(); return; } NihLog.Write(NihLog.Level.Info, "Sending SMS: " + sms.ToString()); WriteToModem("AT+CMGS=\"" + sms.Destination + "\"\r"); System.Threading.Thread.Sleep(500); WriteToModem(sms.Text); byte[] buffer = new byte[1]; buffer[0] = 26; // ^Z modemPort.Write(buffer, offset:0, count:1); CurrentModemState = ModemState.SendingSMS; } public void Dispose() { UninitModem(); } public void HeartBeat() { if (CurrentModemState == ModemState.NotInitialized) { TryInitModem(); return; } if (IsTransitionalState(CurrentModemState) && ModemStateTimeouter.IsTimedOut()) { NihLog.Write(NihLog.Level.Error, "Modem error. Timed out during " + CurrentModemState); CurrentModemState = ModemState.Error; return; } if (CurrentModemState == ModemState.Idle && _lastModemKeepAlive.IsTimedOut()) { // Send keepalive WriteToModem("AT\r"); CurrentModemState = ModemState.KeepAliveAwaitingResponse; return; } if (CurrentModemState == ModemState.Error) { NihLog.Write(NihLog.Level.Debug, "Reenumerating modem..."); UninitModem(); return; } if (_outSmses.Count != 0 && CurrentModemState == ModemState.Idle) { SendSmsNow(); return; } } private string pendingData; private void OnDataReceived() { // Called in the main thread string nowWhat = modemPort.ReadExisting(); pendingData += nowWhat; string[] lines = pendingData.Split(new string[] { "\r\n" }, StringSplitOptions.None); if (lines.Length == 0) { pendingData = string.Empty; return; } else { pendingData = lines[lines.Length - 1]; } // This happens in main thread. for (int i = 0; i < lines.Length - 1; i++) { string line = lines[i]; if (line.Length >= 5 && line.Substring(0, 5) == "+CMT:") { // s+= read one more line if (i == lines.Length - 1) // no next line { pendingData = line + "\r\n" + pendingData; // unread the line continue; } string line2 = lines[++i]; NihLog.Write(NihLog.Level.Debug, "RX " + line); NihLog.Write(NihLog.Level.Debug, "RX " + line2); InboundSMS sms = new InboundSMS(); sms.ParseCMT(line, line2); if(OnNewSMS != null) OnNewSMS(sms); } else // Not a composite NihLog.Write(NihLog.Level.Debug, "RX " + line); if (line == "OK") { OnModemResponse(true); } else if (line == "ERROR") { OnModemResponse(false); NihLog.Write(NihLog.Level.Error, "Modem error"); } } } private void ProcessSmsResult(bool ok) { if (!ok) { OutboundSMS sms = _outSmses.Peek(); if (sms.Attempt < sms.MaxTries) { NihLog.Write(NihLog.Level.Info, "Retrying sms..."); return; } NihLog.Write(NihLog.Level.Error, "Failed to send SMS: " + sms.ToString()); } _outSmses.Dequeue(); } private void OnModemResponse(bool ok) { if (CurrentModemState == ModemState.SendingSMS) ProcessSmsResult(ok); if (!ok) { NihLog.Write(NihLog.Level.Error, "Error during state " + CurrentModemState.ToString()); CurrentModemState = ModemState.Error; return; } switch (CurrentModemState) { case ModemState.NotInitialized: return; case ModemState.PowerUp: WriteToModem("ATE0;+CMGF=1;+CSCS=\"IRA\";+CNMI=1,2\r"); CurrentModemState = ModemState.Initializing; break; case ModemState.Initializing: case ModemState.SendingSMS: case ModemState.KeepAliveAwaitingResponse: CurrentModemState = ModemState.Idle; break; } } private void CloseU9TelitNativeApp() { bool doneSomething; do { doneSomething = false; Process[] processes = Process.GetProcessesByName("wirelesscard"); foreach (Process p in processes) { p.CloseMainWindow(); doneSomething = true; NihLog.Write(NihLog.Level.Info, "Killed native U9 app"); System.Threading.Thread.Sleep(1000); // Will not wait if no native app is started } } while (doneSomething); } void WriteToModem(string s) { modemPort.Write(s); NihLog.Write(NihLog.Level.Debug, "TX " + s); } void UninitModem() { if (modemPort != null) modemPort.Dispose(); modemPort = null; CurrentModemState = ModemState.NotInitialized; } private bool IsTransitionalState(ModemState ms) { return ms == ModemState.Initializing || ms == ModemState.SendingSMS || ms == ModemState.PowerUp || ms == ModemState.KeepAliveAwaitingResponse; } Timeouter _initFailureTimeout = new Timeouter(timeout_s: 10, autoReset:false, timedOut:true); void TryInitModem() { // Try pistoning the modem with higher frequency. This does no harm (such as redundant logging) PrepareU9Modem(); // Will do nothing if modem is okay if (!_initFailureTimeout.IsTimedOut()) return; // Don't try too frequently if (modemPort != null) return; const string modemPortName = "Basecom HS-USB NMEA 9000"; const int speed = 115200; string portName = Hardware.Misc.SerialPortFromFriendlyName(modemPortName); if (portName == null) { NihLog.Write(NihLog.Level.Error, "Modem not found (yet). "); _initFailureTimeout.Reset(); return; } NihLog.Write(NihLog.Level.Info, string.Format("Found modem port \"{0}\" at {1}", modemPortName, portName)); modemPort = new System.IO.Ports.SerialPort(portName, speed); modemPort.ReadTimeout = 3000; modemPort.NewLine = "\r\n"; modemPort.Open(); modemPort.DiscardInBuffer(); modemPort.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(delegate { _mainThreadOwnder.Invoke(dataReceivedDelegate); }); // called in different thread! _lastModemKeepAlive = new Timeouter(60, true); WriteToModem("AT+CFUN=1\r"); CurrentModemState = ModemState.PowerUp; } void CheatU9Telit() { // U9 telit appears as USB CDrom on the bus, until disk eject is sent. // Then, it reappears as normal stuff. VolumeDeviceClass volumeDeviceClass = new VolumeDeviceClass(); foreach (Volume device in volumeDeviceClass.Devices) { if (device.FriendlyName == "PCL HSUPA Modem USB Device") { NihLog.Write(NihLog.Level.Info, "Trying to initialize: " + device.FriendlyName); device.EjectCDRomNoUI(); } } } void PrepareU9Modem() { CloseU9TelitNativeApp(); // Closes the autorun native app CheatU9Telit(); } } public class OutboundSMS { public string Destination; public string Text; public int MaxTries; public int Attempt = 0; public OutboundSMS(string dest, string txt) { Destination = dest; Text = txt; MaxTries = 3; } override public string ToString() { if(Attempt > 1) return string.Format("\"{0}\" to {1}, attempt {2}", Text, Destination, Attempt); else return string.Format("\"{0}\" to {1}", Text, Destination); } } public class InboundSMS { public string SourcePhone; public DateTime ReceiveTime; public string Text; public void ParseCMT(string line1, string line2) { string[] fields = line1.Split(new char[] { ',', ' ', '/', ':', '"' }); if (fields.Length < 12) throw new ApplicationException("CMT message too short. Expected 2 fields"); SourcePhone = fields[3]; ReceiveTime = DateTime.Parse("20" + fields[7] + "-" + fields[8] + "-" + fields[9] + " " + fields[10] + ":" + fields[11] + ":" + fields[12].Substring(0, 2)); //test carefully Text = line2; } }; } 

winforms应用程序中的用法示例:

 Hardware.TeliaModem _modem; public Form1() { InitializeComponent(); _modem = new Hardware.TeliaModem(this); _modem.OnNewSMS += new Hardware.TeliaModem.NewSmsHandler(ProcessNewSMS); _timer.Interval = 1000; // milliseconds _timer.Tick += new EventHandler(OnTimerTick); _timer.Start(); } 

发送短信:

  _modem.SendSMS(sms.SourcePhone, "Aircon is now " + BoolToString.ON_OFF(_aircon.On)); 

在计时器事件上,每秒一次:

 private void OnTimerTick(object o, EventArgs e) { _modem.HeartBeat(); } 

这被注册为Winforms定时器处理程序,以便调制解调器不会有线程。

一些实用程序类使用:

 namespace Utils { public class StopWatch { protected DateTime _resetTime; public StopWatch() { Reset(); } public void Reset() { _resetTime = DateTime.Now; } public double TotalSeconds { get { return (DateTime.Now - _resetTime).TotalSeconds; } } public TimeSpan Time { get { return DateTime.Now - _resetTime; } } }; public class Timeouter : StopWatch { private bool _autoReset; private double _timeout_s; public Timeouter(double timeout_s, bool autoReset, bool timedOut = false) { _timeout_s = timeout_s; _autoReset = autoReset; if (timedOut) _resetTime -= TimeSpan.FromSeconds(_timeout_s + 1); // This is surely timed out, as requested } public bool IsTimedOut() { if (_timeout_s == double.PositiveInfinity) return false; bool timedout = this.TotalSeconds >= _timeout_s; if (timedout && _autoReset) Reset(); return timedout; } public void Reset(double timeout_s) { _timeout_s = timeout_s; Reset(); } public double TimeLeft { get { return _timeout_s - TotalSeconds; } } } } 

我实施了这个,以便通过短信打开空调(是的,我住在一个炎热的国家)。 有用。 请随意使用这些代码。

请享用。

Microsoft在KB文章“ 如何通过使用Visual Basic .NET访问串行和并行端口 ”中提供了一个相当不错的VB.Net示例。 我不确定你的电话返回什么,但是,如果你在示例中更改了缓冲区循环,则至less可以打印出答复:

 MSComm1.Output = "AT" & Chr(13) Console.WriteLine("Send the attention command to the modem.") Console.WriteLine("Wait for the data to come back to the serial port...") ' Make sure that the modem responds with "OK". ' Wait for the data to come back to the serial port. Do Buffer = Buffer & MSComm1.Input Console.WriteLine("Found: {0}", Buffer) Loop Until InStr(Buffer, "OK" & vbCrLf) 

GSMComm是一个C#库,可以让您轻松地与文本或PDU模式下的GSM移动交互。 (该网站还有一堆testing工具)

使用GSM调制解调器发送短信从来不是一个好主意。 这是一个清单,以确保您的短信发送正常。

  • 您正在以文本模式发送短信。 尝试以PDU模式发送。
  • 试试这个库http://phonemanager.codeplex.com/
  • 在发送短信之前,您是否更改SMSC号码 ,如果确定SMSC是正确的。
  • 还要确保你的SIM卡有足够的积分让你发送出站短信。
  • 检查networking状态,尤其是当您从程序发送短信时。 这可能是一个问题。

我build议您免费使用免费版的NowSMS网关Lite版本,让您可以非常顺利地使用GSM调制解调器。 NowSMS会给你一个GSM调制解调器连接的API抽象,所以你只需要调用NowSMS网关的Http Api,其余的将由NowSMS网关来处理。

最重要的是,如果您的最终用户在使用您的应用程序时要保持互联网连接,或者您的应用程序基于networking并通过互联网托pipe,我强烈build议不要使用GSM调制解调器选项并select可靠的Http SMS网关服务提供商