博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用C# 实现串口拨号器的SIM卡通信[修正版]
阅读量:5877 次
发布时间:2019-06-19

本文共 16972 字,大约阅读时间需要 56 分钟。

在第一版 的代码中,存在一些实际的问题,经过反复测试和实际使用,对原代码进行了一些改进。

首先,博客园的同学提出将拨号指令ATD发出后,不必使用 Thread.Sleep(20 * 1000) 方法等待20秒后进行挂机,而改用AutoResetEvent来处理,不必让线程死等,也能提高你程序的性能。但修改后效果并不理想,还是使用Thread.Sleep(20 * 1000) 方法快捷实用。

其次,由于拨号器以及服务器等硬件设备的差异,导致反馈信息的速度不一致,以前采用Thread.Sleep() 方法绑定固定秒数然后查看返回信息的方式存在一定的问题,改用如下代码就行:

复制代码
int i = 0;while (read.Trim() == "" && i <15){    Thread.Sleep(100);    i++;}if (read.Contains("ATH") && read.Contains("OK")){  ......  }
复制代码

其余的不详细介绍,看代码即可。

MySerialPort 类

对每一个连接到COM 串行端口的拨号器实例化 MySerialPort 对象,代码如下:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO.Ports;using System.Threading;namespace Con_SerialPortExample{    public class MySerialPort    {        private SerialPort com;        public MySerialPort(string _portName)        {            this.com = new SerialPort();            //this.autoResetEvent_HasModem = new AutoResetEvent(true);            //this.autoResetEvent_Dialing = new AutoResetEvent(false);            //接收数据事件            this.com.DataReceived += new SerialDataReceivedEventHandler(com_DataReceived);            //串口名            com.PortName = _portName;            this.PortName = _portName;            // BaudRate 串行波特率            com.BaudRate = 9600; //默认值            // 是否启用请求发送 (RTS) 信号。            com.RtsEnable = true; //由计算机发送   Request   To   Send   信号到联接的调制解调器,以请示允许发送数据。            // 是否使Data Terminal Ready (DTR)线有效。  xugang 2012.8.20 添加            //com.DtrEnable = true; //Data   Terminal   Ready   是计算机发送到调制解调器的信号,指示计算机在等待接受传输。             try            {                com.Open();            }            catch //(Exception)            {                Close();            }        }        public MySerialPort(string _portName, int _baudRate)            : this(_portName)        {            if (_baudRate != 0)            {                // BaudRate 串行波特率                com.BaudRate = _baudRate;            }        }        private string portName;        //串口名称        public string PortName        {            get { return portName; }            set { portName = value; }        }        // BaudRate 串行波特率        public int BaudRate        {            get { return com.BaudRate; }            set { com.BaudRate = value; }        }        private bool isWorking;        //设置是否正在使用        public bool IsWorking        {            get { return isWorking; }            set { isWorking = value; }        }        //private enum AutoResetEvent_Type        //{        //   None, HasModem, Dialing        //}        //private AutoResetEvent autoResetEvent_HasModem;        //private AutoResetEvent autoResetEvent_Dialing;        //private AutoResetEvent_Type autoResetEvent_Type = AutoResetEvent_Type.None;        //private bool enableUse;        private DateTime lastUseTime = DateTime.MinValue;        //当前拨号器能否使用 (解决连续使用拨号问题)        public bool EnableUse        {            get             {                TimeSpan span = DateTime.Now - lastUseTime;                return span.TotalSeconds >= 60;             }            //set { enableUse = value; }        }        // 检测当前端口是否安装有拨号器        public bool HasModem()        {            //this.autoResetEvent_Type = AutoResetEvent_Type.HasModem;            //read = ""; //清空返回缓冲区            WriteSerial("AT\r\n");            //Thread.Sleep(500);            //this.autoResetEvent_HasModem.WaitOne(5 * 1000);            //this.autoResetEvent_Type = AutoResetEvent_Type.None;            int i = 0;            while (read.Trim() == "" && i < 40)            {                Thread.Sleep(100);                i++;            }            Console.WriteLine(read.TrimEnd('\r', '\n'));            //Console.Write(read);            //if (read.Contains("AT") && read.Contains("OK"))            if (read.Contains("OK"))            {                Console.WriteLine(this.com.PortName + "端口能使用!");                return true;            }            else            {                Console.WriteLine(this.com.PortName + "端口无法使用!");                return false;            }        }        //进行拨号,唤醒上位机        public void Dialing(string _SIM)        {            IsWorking = true; //正在拨号            try            {                //this.autoResetEvent_Type = AutoResetEvent_Type.Dialing;                read = ""; //清空返回缓冲区                StringBuilder sb = new StringBuilder(36);                sb.Append(this.com.PortName);                sb.Append("端口开始对SIM卡:");                sb.Append(_SIM);                sb.Append(" 进行拨号...");                Console.WriteLine(sb.ToString());                WriteSerial(string.Format("ATD{0};\r\n", _SIM));                System.Threading.Thread.Sleep(20 * 1000);                //this.autoResetEvent_Dialing.WaitOne(20 * 1000);                //this.autoResetEvent_Type = AutoResetEvent_Type.None;                read = ""; //清空返回缓冲区                WriteSerial("ATH\r\n");                //this.autoResetEvent.WaitOne(1000);                int i = 0;                while (read.Trim() == "" && i <15)                {                    Thread.Sleep(100);                    i++;                }                Console.WriteLine(read);                if (read.Contains("ATH") && read.Contains("OK"))                {                    Console.WriteLine(this.com.PortName + "端口拨号已完成!");                }                else                {                    read = ""; //清空返回缓冲区                    //System.Threading.Thread.Sleep(1000);                    WriteSerial("ATH\r\n");                                        //this.autoResetEvent.WaitOne(1000);                    i = 0;                    while (read.Trim() == "" && i < 20)                    {                        Thread.Sleep(100);                        i++;                    }                    Console.WriteLine(read);                    if (read.Contains("ATH") && read.Contains("OK"))                    {                        Console.WriteLine(this.com.PortName + "端口拨号已完成!");                    }                    else                    {                        //IsWorking = false; //拨号完成                        string strExc = this.com.PortName + "拨号异常!";                        Console.WriteLine(strExc);                        throw new Exception(strExc);                    }                }            }            catch (Exception ex)            {                throw ex;            }            finally            {                IsWorking = false; //拨号完成            }        }        ///         /// 向串口端发送命令!        ///         /// 命令字符串        private void WriteSerial(string s)        {            //this.autoResetEvent_HasModem.WaitOne(20*1000);            //mLogger.Info(s);            byte[] buff = Encoding.ASCII.GetBytes(s);            try            {                this.com.Write(buff, 0, buff.Length);            }            catch (Exception ex)            {                //WriteExecLog.Writing(ex);                Console.WriteLine(ex.Message);            }        }        //int n = 0;        string read = "";        //接收数据事件方法        void com_DataReceived(object sender, SerialDataReceivedEventArgs e)        {            if (sender is SerialPort)            {                try                {                    Thread.Sleep(500);                    read = ""; //清空返回缓冲区                    SerialPort mySerial = sender as SerialPort;                    if (mySerial.IsOpen == false)                    {                        mySerial.Open();                    }                    //方法一                    //read += mySerial.ReadLine().Trim();                    //Console.WriteLine(mySerial.PortName + " 第" + n.ToString() + "接收数据:" + read);                    //方法二                    byte[] readBuffer = new byte[1024];                    int count = mySerial.Read(readBuffer, 0, 1023);                    if (count > 0)                    {                        read = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);                        //Console.WriteLine(read);                    }                    //AT 返回                    //if (autoResetEvent_Type == AutoResetEvent_Type.HasModem                    //    && read.Contains("OK"))                    //{                    //    this.autoResetEvent_HasModem.Set();                    //}                    //ATD 返回                    //if (autoResetEvent_Type == AutoResetEvent_Type.Dialing                    //    && (read.Contains("ERROR") || read.Contains("BUSY") || read.Contains("OK") || read.Contains("NO CARRIER"))                    //    )                    //{                    //    this.autoResetEvent_Dialing.Set();                    //}                }                catch (TimeoutException)                {                    return;    //xg备忘:可以将异常写入日志!                }                catch (Exception)                {                    return;    //xg备忘:可以将异常写入日志!                }                //finally                //{                //    this.autoResetEvent_HasModem.Set();                //}            }        }        //private string ReadSerial()        //{        //    while (_keepReading)        //    {        //        if (com.IsOpen)        //        {        //            //byte[] readBuffer = new byte[com.ReadBufferSize + 1];        //            byte[] readBuffer = new byte[10];        //            try        //            {        //                //int count = com.Read(readBuffer, 0, com.ReadBufferSize);        //                int count = com.Read(readBuffer, 0, 9);        //                String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);        //                if (count != 0)        //                {        //                    return SerialIn;        //                }        //            }        //            catch (TimeoutException)         //            {        //                return "";        //            }        //        }        //        else        //        {        //            TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);        //            Thread.Sleep(waitTime);        //        }        //    }        //    return "";        //}        //关闭        public void Close()        {            if (com != null)            {                com.Close();                com.Dispose();            }        }    }}
复制代码

SerialPortList 类

定义一个 SerialPortList 类,实现对所有连接上的拨号器 MySerialPort 对象进行管理和调度使用。代码如下:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.IO.Ports;using System.Threading;namespace Con_SerialPortExample{    public class SerialPortList    {        //已经安装了拨号器的串口对象        private List
al = null; //可使用的拨号器个数 public int WorkableCount { get { if (al == null) return 0; else return al.Count; } } private Dictionary
portBaudRate = null; //波特率配置列表 public Dictionary
PortBaudRate { get { return portBaudRate; } set { portBaudRate = value; } } private bool hasPort = false; //当前有无可使用的串口拨号器 public bool HasPort { get { return hasPort; } //set { hasPort = value; } } private int reCheckMinutes = 30; //默认30分钟 //串口拨号器的重新检测间隔分钟 public int ReCheckMinutes { get { return reCheckMinutes; } set { reCheckMinutes = value; } } #region 构造方法重载 public SerialPortList() { } public SerialPortList(Dictionary
_portBaudRate) { this.portBaudRate = _portBaudRate; } public SerialPortList(int _reCheckMinutes) { this.reCheckMinutes = _reCheckMinutes; } public SerialPortList(Dictionary
_portBaudRate, int _reCheckMinutes) { this.portBaudRate = _portBaudRate; this.reCheckMinutes = _reCheckMinutes; } #endregion 构造方法重载 ///
/// 获得串口上已经安装了拨号器的对象 /// public void GetSerialPortList() { al = new List
(); //步骤一: 获得所有的串口名称(列表) string[] ports = SerialPort.GetPortNames(); foreach (string port in ports) { MySerialPort mySerialPort = null; Console.WriteLine("正在检测:" + port); //测试使用 //是否设置波特率? if (portBaudRate != null && portBaudRate.ContainsKey(port) && portBaudRate[port] != 0) { mySerialPort = new MySerialPort(port, portBaudRate[port]); } else mySerialPort = new MySerialPort(port); bool ok = mySerialPort.HasModem(); if (ok) { al.Add(mySerialPort); } else { mySerialPort.Close(); mySerialPort = null; } } // 判断当前计算机有无可使用串口端 hasPort = al.Count <= 0 ? false : true; } ///
/// 重新获得串口上已经安装了拨号器的对象 /// public void ReGetSerialPortList() { if (al == null) GetSerialPortList(); else { //步骤一: 重新获得所有的串口名称(列表) string[] portsName_2 = SerialPort.GetPortNames(); //如果当前串口数目 > 正在使用的COM if (portsName_2.Length > al.Count) { Console.WriteLine("正在重新检测可以使用的拨号器!"); //测试使用 foreach (string pName_2 in portsName_2) { //当前串口名是否存在拨号列表中 bool hasAt = al.Exists(delegate(MySerialPort port_1) { return pName_2 == port_1.PortName; }); //如果当前串口名不存在拨号列表中,则重新检测! if (!hasAt) { Console.WriteLine("正在重新检测:" + pName_2); //测试使用 MySerialPort mySerialPort = null; //是否设置波特率? if (portBaudRate != null && portBaudRate.ContainsKey(pName_2) && portBaudRate[pName_2] != 0) { mySerialPort = new MySerialPort(pName_2, portBaudRate[pName_2]); } else mySerialPort = new MySerialPort(pName_2); bool ok = mySerialPort.HasModem(); if (ok) { al.Add(mySerialPort); } else { mySerialPort.Close(); mySerialPort = null; } } } } } // 判断当前计算机有无可使用串口端 hasPort = al.Count <= 0 ? false : true; } ///
/// 重新获得串口上已经安装了拨号器的对象 (波特率使用默认值) /// public void ReGetSerialPortList(int _reCheckMinutes) { //串口拨号器的重新检测间隔分钟 reCheckMinutes = _reCheckMinutes; ReGetSerialPortList();//波特率全部使用默认值 } ///
/// 释放所有串口资源组件 /// public void ClearAllSerialPort() { if (al != null) { for (int i = 0; i < al.Count; i++) { al[i].Close(); al[i] = null; } al = null; } if (portBaudRate != null) { portBaudRate = null; } } private int index_Number = -1; //串口的调度号 private int IndexNumber() { lock (this) { if (index_Number + 1 >= al.Count) { if (al.Count == 0) index_Number = -1; else index_Number = 0; } else { index_Number++; } return index_Number; } } ///
/// 对已经安装了拨号器的串口调度使用 /// private void UseingSerialPort(string _SIM) { if (al == null) return; // 等待线程进入 Monitor.Enter(al); MySerialPort getPort = null; try { //获得当前调用的串口对象的索引号 int num = IndexNumber(); if (num >= 0) //判断是否存在拨号器 { getPort = al[num]; if (getPort != null && !getPort.IsWorking) { getPort.Dialing(_SIM); //对 SIM 进行拨号,唤醒上位机 } } else { //没有可使用的拨号器,则重新检测。 this.ReGetSerialPortList(); } } catch { //再一次检查该 COM 能否使用! (范工提议) if (getPort != null) { string re_PortName = getPort.PortName; al.Remove(getPort); //从可用列表去除 getPort.Close(); MySerialPort mySerialPort = new MySerialPort(re_PortName); bool ok = mySerialPort.HasModem(); if (ok) { al.Add(mySerialPort); //重新添加到列表 } else { mySerialPort.Close(); mySerialPort = null; } } } finally { // 通知其它对象 Monitor.Pulse(al); // 释放对象锁 Monitor.Exit(al); } } //重新检测端口时间 private DateTime dtCheck = DateTime.Now; ///
/// 调用拨号器 /// ///
public void InvokingSerialPort(string _SIM) { if (hasPort == false) { // 获得串口上已经安装了拨号器的对象 this.GetSerialPortList(); } if (hasPort == true) { this.UseingSerialPort(_SIM); //Thread.Sleep(5000); } //定期检测串口列表 //if (dtCheck.AddMinutes(reCheckMinutes) <= DateTime.Now) if (dtCheck.AddMinutes(5) <= DateTime.Now) { // 重新获得串口上已经安装了拨号器的对象 this.ReGetSerialPortList(); dtCheck = DateTime.Now; } } }}
复制代码

测试代码如下:

复制代码
using System;using System.Collections.Generic;using System.Linq;using System.Text;////using System.IO.Ports;using System.Threading;//using System.Collections;namespace Con_SerialPortExample{    class Program    {        static void Main(string[] args)        {            // 获得串口上已经安装了拨号器的对象 (自定义波特率)            Dictionary
_portBaudRate = new Dictionary
(); _portBaudRate["COM1"] = 9600; _portBaudRate["COM2"] = 9600; _portBaudRate["COM7"] = 9600; SerialPortList list = new SerialPortList(_portBaudRate,5); try { // 获得串口上已经安装了拨号器的对象 list.GetSerialPortList(); if (list.HasPort == false) { Console.WriteLine("当前计算机无可使用的串口拨号器!"); } while (list.HasPort) { // 调用拨号器 list.InvokingSerialPort("13500000000"); Thread.Sleep(5000); } Console.WriteLine("程序运行结束!"); } finally { // 释放所有串口资源组件 list.ClearAllSerialPort(); } Console.ReadLine(); } }}本文转自钢钢博客园博客,原文链接http://www.cnblogs.com/xugang/archive/2012/09/19/2693856.html,如需转载请自行联系原作者
你可能感兴趣的文章
SCDPM2012 R2实战一:基于SQL 2008 R2集群的SCDPM2012 R2的安装
查看>>
SQL SERVER中字段类型与C#数据类型的对应关系
查看>>
Linux lsof命令详解
查看>>
SVG path
查看>>
js判断checkbox是否选中
查看>>
多系统盘挂载
查看>>
MySQL函数怎么加锁_MYSQL 函数调用导致自动生成共享锁问题
查看>>
MR1和MR2的工作原理
查看>>
Eclipse中修改代码格式
查看>>
GRUB Legacy
查看>>
关于 error: LINK1123: failure during conversion to COFF: file invalid or corrupt 错误的解决方案...
查看>>
python实现链表
查看>>
java查找string1和string2是不是含有相同的字母种类和数量(string1是否是string2的重新组合)...
查看>>
Android TabActivity使用方法
查看>>
Eclipse的 window-->preferences里面没有Android选项
查看>>
《麦田里的守望者》--[美]杰罗姆·大卫·塞林格
查看>>
遇到的那些坑
查看>>
央行下属的上海资信网络金融征信系统(NFCS)签约机构数量突破800家
查看>>
[转] Lazy evaluation
查看>>
常用查找算法总结
查看>>