C#で.NetアプリケーションからSMSを送信します



SMSを送信するために必要なのは、3G USBモデム、SIMカード、Visual Studio、そして少しの時間だけです。 私の目標は、COMポートまたはPDU形式のすべての可能な設定を説明することではありません。 私のプロジェクトでスニペットとして使用できるターンキーソリューションを提供したいと思います。

例として、2つのコンソールアプリケーションを考えます。 なぜコンソールなのか? はい、それらに余分なものはなく、コードを解析するのが簡単だからです。 なぜ2つ? メッセージを送信するための2つの一般的なオプションがあるためです。 最も簡単なオプションは、テキストモードでメッセージを送信することです。 このオプションの欠点は、キリル文字の送信をサポートしていないことです。 プラスは、160文字を送信できることです。 より複雑な2番目のオプションでは、最大70文字のテキストをUnicode形式で送信できます。



テキストモードでメッセージを送信します。



そこで、コンソールアプリケーションを作成し、まず名前空間を追加します。

using System.IO.Ports;
      
      





次に、SerialPort型の変数を宣言します

 static SerialPort port;
      
      





アプリケーションはコンソールであるため、静的です。



メインアプリケーションプロシージャstatic void Main(string [] args)内で、新しいSerialPort()コンストラクターを使用して変数を初期化します

 port = new SerialPort();
      
      





ポート設定のインストールとそのオープンを別の手順で取り出します。

  private static void OpenPort() { port.BaudRate =2400; //   4800, 9600, 28800  56000 port.DataBits = 7; //   8, 9 port.StopBits = StopBits.One; //   StopBits.Two StopBits.None  StopBits.OnePointFive port.Parity = Parity.Odd; //   Parity.Even Parity.Mark Parity.None  Parity.Space port.ReadTimeout = 500; //     port.WriteTimeout = 500; //     port.Encoding = Encoding.GetEncoding("windows-1251"); port.PortName = "COM5"; //      if (port.IsOpen) port.Close(); //        try { port.Open(); } catch (Exception e) { } }
      
      





設定は異なるモデムに固有の場合があります。 Huawei E150モデルでテストを実施し、同時にほぼすべての設定で送信を実行しました。

すべての設定は、MSDNのこのリンクから入手できます

ポート番号は、デバイスマネージャーを使用して決定されます。 次の例はCOM4ポートです。



ポートが開いたら、ATコマンドを使用してメッセージの送信を開始できます。

port.WriteLineを使用してコマンドをモデムに送信します。 コマンドを送信する間、System.Threading.Thread.Sleep(500)を一時停止してください。



最初の2つのチームを送信しましょう。

  port.WriteLine("AT \r\n"); //  !   System.Threading.Thread.Sleep(500); port.Write("AT+CMGF=1 \r\n"); //       System.Threading.Thread.Sleep(500);
      
      





最初のコマンドは、モデムにスタンバイモードに入るように要求します。 2番目のコマンドは、メッセージ送信のテキストモードを設定します。 コマンドの後に改行文字\ r \ nがあることに注意してください。 ネットワーク上で見つけることができるメッセージ送信のさまざまな例では、さまざまな転送が示されています。 どこかで\ r、どこかで\ n、時には\ n \ rです。 MSDNの公式情報によると:

Environment.NewLineは、非UNIXプラットフォームの場合は「\ r \ n」を含む文字列、Unixプラットフォームの場合は「\ n」を含む文字列です。 つまり、この場合、\ r \ nを使用します。



簡略化するには、SIMカードのPINコードチェックを無効にします。 これは、モデムに付属のアプリケーションを使用するか、携帯電話を使用して実行できます。

コマンドのパラメーターとしてモデムに渡される電話番号には、数字と「+」記号以外の文字を含めることはできません。 つまり、国際形式で送信する必要があります。 SMS受信者の電話番号を使用してコマンドを送信します。

 port.Write("AT+CMGS=\"+375123456789\"" + "\r\n"); System.Threading.Thread.Sleep(500);
      
      





そして、メッセージ自体のテキストを送信します。

 port.Write("Hello from modem!" + char.ConvertFromUtf32(26) + "\r\n"); System.Threading.Thread.Sleep(500);
      
      





メッセージテキストの後にchar.ConvertFromUtf32(26)が渡されることに注意してください。

ATコマンドを送信するとき、CTRL-Zの組み合わせを送信する必要があるのは、メッセージ自体のテキストを送信した後です。 この組み合わせは、UTF32の26番目の文字です。

メッセージが送信された後、ポートを閉じることは正しいでしょう

 port.Close();
      
      





コマンドを送信した後、通常、モデムは確認またはエラーで応答を返します。 このデータは、モデム応答の文字列値を返すport.ReadExisting()メソッドを使用して読み取ることができます。

ポートを開く手順では、ポートがデータを受信したときにイベントの登録を追加できます。

 port.DataReceived += SerialPortDataReceived;
      
      





さらに、データ処理を実装します。

  private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e) { //       }
      
      





プログラムは単一のスレッドで実行されます。 1つのスレッドでCOMポートを操作することをお勧めします。 これを行うには、 [STAThread]属性でクラス/コードをマークできます。 COMポートを使用したマルチスレッド処理に関する詳細を知っている人がいれば、喜んでコメントします。



Githubリンク

リンクをダウンロードできます



メッセージをテキストとして送信することは、ネット上で非常に人気のあるトピックです。 また、テキストの送信ですべてが明らかな場合、PDUモードでメッセージを送信するときに、常に開示されているとは限らない疑問が生じます。



PDUモードでのメッセージの送信(プロトコルデータユニット)



ポートを開くことは、上記の例のポートを開くこととまったく同じです。

最初の2つのコマンドも前の例と似ていますが、2番目のコマンドではパラメーターとして0が渡されます。

 port.WriteLine("AT\r\n"); //  "!"   System.Threading.Thread.Sleep(500); port.Write("AT+CMGF=0\r\n"); //    PDU    System.Threading.Thread.Sleep(500);
      
      





PDUの形式でメッセージを送信する場合、携帯電話番号に数字以外を含めることはできません。 桁数が奇数の場合は、最後に数字Fを追加し、さらに隣接する数字を並べ替える必要があります。 たとえば、SMSの受信者番号は1234567で、桁数は奇数です。これは、Fを追加することを意味します。順列を実行し、214365F7を取得します。

次の関数は、この変換を行うのに役立ちます。

  //      PDU public static string EncodePhoneNumber(string PhoneNumber) { string result = ""; if ((PhoneNumber.Length % 2) > 0) PhoneNumber += "F"; int i = 0; while (i < PhoneNumber.Length) { result += PhoneNumber[i + 1].ToString() + PhoneNumber[i].ToString(); i += 2; } return result.Trim(); }
      
      





メッセージ自体もUCS2形式でエンコードする必要があります。 この形式は、UTF-16形式の廃止バージョンです。 違いは、UCS2は余分な文字の互換性のある表現に使用できないことです。 FAQリンク

簡単に言えば、UTF-16とUCS2のコードはほとんど同じです。

シンボルコードは、[スタート]メニューの[すべてのプログラム]-[標準]-[ユーティリティ]-[シンボルテーブル]にあるシンボルテーブルで表示または確認できます。



文字「e」のコード-0435

ネットワークの一部の例では、文字をコードに一致させることで、文字からコードへの変換が行われます。 つまり、文字の配列と対応する文字コードの配列が作成されます。 メッセージテキストの各文字はコードに置き換えられます。 この例は機能しますが、私は別のものを好みました:

 //     UCS2 public static string StringToUCS2(string str) { UnicodeEncoding ue = new UnicodeEncoding(); byte[] ucs2 = ue.GetBytes(str); int i = 0; while (i < ucs2.Length) { byte b = ucs2[i + 1]; ucs2[i + 1] = ucs2[i]; ucs2[i] = b; i += 2; } return BitConverter.ToString(ucs2).Replace("-", ""); }
      
      





すべてが比較的単純に思えますが、そこにはありませんでした! 暗号化された電話番号とメッセージとともに、多くの情報を転送する必要があります。



電話番号を含むtelnumber文字列変数(国際形式で「+」文字のない数字のみ)があるとします。 電話番号のコードを作成します。

 telnumber = "01"+"00" + telnumber.Length.ToString("X2") + "91" + EncodePhoneNumber(telnumber);
      
      





「01」はPDUタイプ、またはSMS-SUBMITと呼ばれることもあります。 01は、メッセージが送信されているが受信されていないことを意味します

このTP-Message-Referenceの「00」は、電話/モデムが成功したメッセージの数を自動的に設定できることを意味します

telnumber.Length.ToString( "X2")は、数値の長さを16進数で示します

「91」は、国際電話番号形式が使用されることを意味します

EncodePhoneNumberは上記の関数です。



次に、textsms変数にメッセージテキストを指定して、メッセージ自体のコードを取得します。

 textsms = StringToUCS2(textsms);
      
      





次に、このメッセージの長さを16進形式で取得する必要があります。 このようになります:

 string leninByte = (textsms.Length / 2).ToString("X2");
      
      







電話番号のコード、メッセージの長さ、メッセージコードを組み合わせて、これにすべての中間コードシンボルを追加します。

 textsms = telnumber + "00"+"0"+"8" + leninByte + textsms;
      
      





「00」は、メッセージ形式が暗黙的であることを意味します。 これはプロトコル識別子です。 その他のオプションは、テレックス、テレファックス、ボイスメッセージなどです。

0ではなく1を指定すると「0」になり、メッセージは電話に保存されません。 フラッシュメッセージがポップアップ表示されます。

「8」はUCS2形式-文字あたり2バイトを意味します。



以前は、電話番号とメッセージテキストの長さはすでに考慮されていました。 今度は、PDUメッセージ全体の長さを計算する必要があります。 ATコマンドでこの長さを送信します。

 double lenMes = textsms.Length / 2; //       port.Write("AT+CMGS=" + (Math.Ceiling(lenMes)).ToString() + "\r\n"); System.Threading.Thread.Sleep(500);
      
      





2行目は切り上げを使用しています。 たとえば、15.5オクテットを取得した場合でも、16オクテットのパケットでデータを転送します。



この非常に紛らわしいPDUコードは、サービスプロバイダーのSMSセンター番号を転送する必要があるという事実で終わります。 現在、ほとんどすべてのSIMカードには既に「有線」センター番号が含まれているため、この番号の代わりにコード「00」を渡します。これは、番号がSIMカードデータから自動的に取得されることを意味します。

このコード「00」は、メッセージの最初にあるはずです。 奇妙なことに、これらの文字はメッセージの最初にありますが、最後のステップで追加する必要があります。 その理由は、このコードを考慮せずにメッセージの長さを計算しなければならなかったからです。

 textsms = "00" + textsms;
      
      





それだけです 次のコマンドでAT PDUコードを送信できます。

 port.Write(textsms + char.ConvertFromUtf32(26) + "\r\n"); //     CTRL-Z   System.Threading.Thread.Sleep(500);
      
      





Githubリンク



All Articles