文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>个人项目QXin局域网通讯工具|分层架构的体会

个人项目QXin局域网通讯工具|分层架构的体会

时间:2010-08-21  来源:Xingg

项目名称:QXin局域网通信      (兼容飞鸽,飞秋等局域网通信)

 

程序架构:

WinForm .net 4.0

 

功能点:

一、日常提示

上下线提示,更新获取局域网QXin用户列表,正在输入提示、类QQ界面模式

二、字符串通信

 单用户字符串通信、多用户字符串广播

三、文件通信

单用户单文件传送,单文件夹传送、多文件多文件夹混合传送。

多用户广播传送

 

程序实现过程:

UDP通信:(上下线提示,字符串通信)

一发一回的方式,例如:用户A上线,以广播的方式发送“我上线啦”的消息,其他用户接收后把该用户加添到用户列表里,返回一个“已收到”信息,用户A接收到各个用户返回的信息并一一加载到用户列表。

TCP通信:(文件传送)

首先用户A以UDP方式通知用户B,”我要发送某某文件”,用户B接收后,AB用户开始进行TCP连接,然后发送文件

单文件发送和文件夹发送差别很大,由于文件夹不是文件,只能通过发送消息通知远程用户在什么地方建立一个文件夹,然后送该文件夹下的文件。如果该文件夹有子文件夹,又系同样的方式通知远程用户在哪个文件里新建子文件夹,不断递归。

(PS:飞鸽协议是开源的,不过飞秋可不是,飞秋虽然同样采用飞鸽协议,但是在此基础上增加修改了不少内容,要兼容飞秋需要用WPE抓包分析飞秋的数据包。)

 

分层架构模式思想:

所谓分层架构,分层架构并不是一个程序分几个模块或者源文件就是分层架构,分层架构是一种模式,分层架构必须只能自上往下操作,下层不知上层的内容,上层只能调用其下层的函数,UI层调用BLL层,BLL层调用DAL层. 而BLL层是绝不可以调用UI层的. 例如BLL层绝不能出现MessageBox等winform方法。而且,要做到BLL和DAl 在脱离UI表面层后,转到控制台通过调用其类和方法也能正常运行,才算好的分层架构。

 

编写体会总结:

在编写QXin的过程中,实现功能的同时要时刻兼顾分层结构的模式确实带来不少的麻烦,很多时候,在完成某个功能点后,发现UI层还带着BLL层的操作,就得重写一次,把属于BLL的操作剥出来,好在VS有封装方法,替换名字的贴心功能.

 

某些遇到过的问题:

第一:文件传输进度显示问题

 文件传输属于BLL,同时必须开辟多线程与远程端口通信, BLL层又不能直接对UI层的ProgressBar等控件进行操作,如何实时反馈给UI层呢?

猜想一:方法返回值形式,这个首先否定了, 以方法返回值形式是行不通的,文件传输比较开辟线程,UI层调用BLL层以后就继续往下执行了,不会等线程方法返回。结论:不能使用。

猜想二:以变量参数指针方式传给方法,在传输文件的线程中不断给变量赋值,UI便可从中取出传输文件的信息,方可显示到Progressbar上。 但是要实时显示进度还必须开辟一个线程对Progressbar进行控制,而且两个线程对同一个变量操作很容易造成并发问题。结论:不是最佳。

猜想三:以委托方式(C#)作为方法的参数传给入BLL层,在BLL层上传参数调用此委托/方法,即可即保持分层架构,亦可以对UI进行间接控制。结论:最佳。

Q1:猜想三那BLL还不是操作了UI层,怎算保持分层架构?

A1:对控件操作的方法/方法定义还是保持在UI层上,例如在WinForm下UI层定义此方法包含Messagebox方法,换到控制台里运行,改成Console.WriteLine方法,不必修改BLL就可以用了。

 

第二:多线程回收问题

在多文件传输中,如:

UI中:

 private void btSend_Click(object sender, EventArgs e)    //只对UI层进行直接操作

{

      Thread ThreSendFiles =new Thread(new ThreadStart(delegate() {

      Foreach(ListViewItem Item in ListView.SelectItems)  //遍历选择的文件发送

{

     QXin. SendFile((QXinFile) Item.Tap);   //调用BLL的发送文件方法

}

}));

ThreSendFiles. IsBackground=true;

ThreSendFiles.Start();

}

 

BLL中:

void SendFile (QXinFile fileItem)

{

     

      TcpListener   tcpListener = new TcpListener(IPAddress.Any, MyPoint);

      tcpListener.Start();

Socket TcpConnect = tcpListener.AcceptSocket();

//…..

TcpConnect.Dispose();

tcpListener.Stop();

}

 

假定我想实现在传输过程中,按取消按钮,马上断开连接,停止线程运行。于是我在

UI中:

private void btCancelSend_Click(object sender, EventArgs e)

{

        ThreSendFiles.Abort();

       ThreSendFiles = null;

       GC.Collect();

}

原本以为结束线程,调用GC.Collect()后就万事OK,结果当再次发送文件的时候,抛出端口不能重复绑定的异常。原来线程还在运行。思来想去,最好的方法是把TcpListener   和Socket等类定义为字段,在BLL中提供方法供UI断开连接。

BLL中:

TcpListener tcpListener;

Socket TcpConnect;

public void Collect()

{

            if (tcpListener != null)

            {

                tcpListener.Stop();

            }

            if (TcpConnect != null)

            {

                TcpConnect.Dispose();

            }

}

UI中:

private void btCancelSend_Click(object sender, EventArgs e)

{

        ThreSendFiles.Abort();

       ThreSendFiles = null;

       QXin.Collect();

}

 

以上是我对分层架构模式的理解,如有错误,望请指点。

相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载