RFID会议签到系统总结(十)――客户端通讯组件

 

上一篇Socket封装只是一个技术的封装,是为了隐藏一些技术细节,这一篇主要是通讯组件的逻辑封装。

这里基本没有什么可谈的,只是到处调用上一篇里的方法而已。比如读取配置连接远程主机啦,关闭Socket连接啦,组合字符串发送命令啦等。

这个地方最费事的是SocketPackOnReceive事件的处理,这个事件在Socket接收到远程主机的命令时会触发。

       private void winsock_OnReceive(object sender, ComReceiveEventArgs e) {

           try

           {

              string msg = e.ComData;

 

              logNetForInfo.Info("From [" + Host + "] Data:" + msg);

 

              int commandEndIndex = 0;

              int dataEndIndex = 0;

              int oldDataIndex = 0;

              string command = "";

              string data = "";

 

              while(true)

              {  

                  #region 解析指令与数据部分

                  commandEndIndex = msg.IndexOf(CommandConst.COMMANDTOKEN,dataEndIndex);

                  if (commandEndIndex < 0) break;

                  oldDataIndex = dataEndIndex;

                  dataEndIndex = msg.IndexOf(CommandConst.DATATOKEN,commandEndIndex);

                  if (dataEndIndex < 0) break;

 

                  if (oldDataIndex == 0)

                     command = msg.Substring(0,commandEndIndex);

                  else

                     command = msg.Substring(oldDataIndex + CommandConst.DATATOKENLENGTH,commandEndIndex - oldDataIndex - CommandConst.DATATOKENLENGTH);

 

                  data = msg.Substring(commandEndIndex + CommandConst.COMMANDTOKENLENGTH,dataEndIndex - commandEndIndex - CommandConst.COMMANDTOKENLENGTH);

                  #endregion

 

                  ProcessData(command,data);

              }

 

 

           }

           catch(Exception ex)

           {

              logNet.Error(" [" + Host + "]读取数据时发生错误:" + ex.Message);

           }

       }

上面没什么可以特别一书的东西,就是字符串运算,很笨的方法。然后下面处理解析得的数据

       private void ProcessData(string command,string data)

       {

           #region 根据不同指令触发不同事件

           switch(command)

           {

              case CommandConst.BEGINSIGNIN://开始签到

                  if (BeginSignInEvent != null)

                     ThreadingEvent.Invoke(BeginSignInEvent,new object[]{this,new BeginSignInEventArgs(true)});

                  break;

              //......

              //............

              //......

              case CommandConst.DOWNLOADDB://下载数据库

                  if (DownLoadDBEvent != null)

                      DownLoadDBEvent.BeginInvoke(this,System.EventArgs.Empty,new AsyncCallback(DownLoadDBResult),null);

                  break;

              default:

                  if (DataReceive != null)//其他命令

                     ThreadingEvent.Invoke(DataReceive,new object[]{this,new ComReceiveEventArgs(data)});

                  break;

           }

           #endregion

       }

 

我们注意到上头事件的触发有时没有用通常的写法,而是用ThreadingEvent.Invoke。因为在.net里在辅助线程上是无法执行方法来修改窗体UI的,要修改UI只能在窗体自身的线程上执行。由于系统中运用的一些组件多是在各个不同的线程中运行,甚至组件本身运行在很多的线程上,这其中有很多事件都涉及到UI的改变。而按我们通常的写法,那些事件代码都将会在触发这个事件的线程里执行,那样的话无法改变UI。所以写了个事件触发的通用写法,只要有可能涉及到修改UI的事件都通用它来触发。

      public sealed class ThreadingEvent

      {

             public static void Invoke(Delegate eventDelegate,object[] param)

             {

                    Control ctr = eventDelegate.Target as Control;

                    if (ctr != null)

                    {

                           if (ctr.IsHandleCreated)

                                  ctr.Invoke(eventDelegate,param);

                    }

                    else

                           eventDelegate.DynamicInvoke(param);

             }

      }

有点不完善的地方,没有再写一个用于异步调用的方法,因为在else这个条件时,Delegate的异步调用不知该怎么写。不过还好现在看来那些同步触发的事件也没造成系统的什么大问题,所以就这样将就用了。

 

最后不要忘了,还有一个Socket连接可用性的监测,如果有变化,还记得要向外部触发事件,这个比较简单,就不去讲述了。

原文地址:https://www.cnblogs.com/lichdr/p/797932.html