c#c/s模式
2012-08-03 10:30:43 zxy838279821 阅读数 807

1、C#客户端和java后台的数据交互相关:

 数据交互使用到的技术是:restlet

通过java后台将 需要的数据做成一个resource,而客户端通过URL访问对应Resource的地址从而得到对应的数据。

给个例子程序:如下

进入http://download.csdn.net/detail/zxy838279821/4473523此地址下载相关java后台Restlet工程示例

2010-04-17 11:56:00 wl_ldy 阅读数 8014

I)背景:

      在很多系统中即包含B/S架构也包括C/S架构,这就涉及到B/S与C/S进行通讯的问题,关于这个问题我也在CSDN的论坛中专门拿出来

  和各位的高手进行了讨论,具体的帖子:http://topic.csdn.net/u/20100326/09/dd9ee3ce-3d90-4583-8eaf-d8542d7eec72.html

总的来说,提供了两种解决方案:

       1)通过WebService进行通讯 。      2)通过WCF进行通讯

但是关于WebService和WCF的知识懂的不太多,于是从另外一个方法进行了考虑,使用Socket进行通讯。

II)服务器端的测试代码:

 


 

 


 


 

 

 

III)客户端代码:

 

 

IV)参考的例子:

     http://blog.csdn.net/zhoufoxcn/archive/2009/03/18/4000301.aspx

     http://blog.csdn.net/lyd_253261362/archive/2009/07/30/4394370.aspx

2011-08-16 11:55:27 javaweb_research 阅读数 626
 1 前言 

 长期以来,广大程序员为到底是使用Client/Server,还是使用Browser/Server结构争论不休,在这些争论当中,C/S结构的程序可维护性差,布置困难,升级不方便,维护成本高就是一个相当重要的因素。有很多企业用户就是因为这个原因而放弃使用C/S。然而当一个应用必须要使用C/S结构才能很好的实现其功能的时候,我们该如何解决客户端的部署与自动升级问题?部署很简单,只要点击安装程序即可,难的在于每当有新版本发布时,能够实现自动升级[3]。现在好了,我们的目标很简单,我们希望开发一个与具体应用无关的能够复用的自动升级系统。下面我为大家提供了一套可复用的用C#编写的自动升级系统。 

2 实现软件的自动升级存在的困难 

 第一,为了查找远程服务器上的更新,应用程序必须有查询网络的途径,这需要网络编程、简单的应用程序与服务器通讯的协议。

 第二是下载。下载看起来不需要考虑联网的问题,但要考虑下载用户请求的文件,以及在没有用户同意时下载大文件。友好的自动更新应用程序将使用剩余的带宽下载更新。这听起来简单,但却是一个技术难题,幸运的是已经有了解决方法。

 第三个考虑因素是使用新版应用程序更换原应用程序的过程。这个问题比较有趣,因为它要求代码运行时将自己从系统删除,有多种办法可以实现该功能[5],本文程序主要通过比较新旧版本的日期号来实现替换新版本应用程序的功能。 

3 实现软件自动在线升级的原理 

 写两个程序,一个是主程序;一个是升级程序;所有升级任务都由升级程序完成。

 1.启动升级程序,升级程序连接到网站,下载新的主程序(当然还包括支持的库文件、XML配置文档等)到临时文件夹;

 2.升级程序获取服务器端XML配置文件中新版本程序的更新日期或版本号或文件大小;

 3.升级程序获取原有客户端应用程序的最近一次更新日期或版本号或文件大小,两者进行比较;如果发现升级程序的日期大于原有程序的最新日期,则提示用户是否升级;或者是采用将现有版本与最新版本作比较,发现最新的则提示用户是否升级;也有人用其它属性如文件大小进行比较,发现升级程序的文件大小大于旧版本的程序的大小则提示用户升级。本文主要采用比较新旧版本更新日期号来提示用户升级。

 4.如果用户选择升级,则获取下载文件列表,开始进行批量下载文档;

 5.升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;

 6.删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;

 7.检查主程序的状态,若状态为活动的,则启动新的主程序;

 8.关闭升级程序,升级完成[4]。  

4 用C#实现在线升级的关键步骤 
这里我主要使用日期信息来检测是否需要下载升级版本。 
4.1 准备一个XML配置文件 
名称为AutoUpdater.xml,作用是作为一个升级用的模板,显示需要升级的信息。 
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><?xml version="1.0"?> //xml版本号 <AutoUpdater> <URLAddres URL="http://192.168.198.113/vbroker/log/"/>//升级文件所在服务器端的网址 <UpdateInfo> <UpdateTime Date = "2005-02-02"/> //升级文件的更新日期 <Version Num = "1.0.0.1"/> //升级文件的版本号 </UpdateInfo> <UpdateFileList> //升级文件列表 <UpdateFile FileName = "aa.txt"/> //共有三个文件需升级 <UpdateFile FileName = "VB40.rar"/> <UpdateFile FileName = "VB4-1.CAB"/> </UpdateFileList> <RestartApp> <ReStart Allow = "Yes"/> //允许重新启动应用程序 <AppName Name = "TIMS.exe"/> //启动的应用程序名 </RestartApp> </AutoUpdater>
 从以上XML文档中可以得知升级文档所在服务器端的地址、升级文档的更新日期、需要升级的文件列表,其中共有三个文件需升级:aa.txt、VB40.rar、VB4-1.CAB。以及是否允许重新启动应用程序和重新启动的应用程序名。
4.2 获取客户端应用程序及服务器端升级程序的最近一次更新日期 
通过GetTheLastUpdateTime()函数来实现。
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->private string GetTheLastUpdateTime(string Dir) { string LastUpdateTime = ""; string AutoUpdaterFileName = Dir + @"\AutoUpdater.xml"; if(!File.Exists(AutoUpdaterFileName)) return LastUpdateTime; //打开xml文件 FileStream myFile = new FileStream(AutoUpdaterFileName,FileMode.Open); //xml文件阅读器 XmlTextReader xml = new XmlTextReader(myFile); while(xml.Read()) { if(xml.Name == "UpdateTime") { //获取升级文档的最后一次更新日期 LastUpdateTime = xml.GetAttribute("Date"); break; } } xml.Close(); myFile.Close(); return LastUpdateTime; }
 通过XmlTextReader打开XML文档,读取更新时间从而获取Date对应的值,即服务器端升级文件的最近一次更新时间。 

函数调用实现: 
//获取客户端指定路径下的应用程序最近一次更新时间 
string thePreUpdateDate = GetTheLastUpdateTime(Application.StartupPath); 
Application.StartupPath指客户端应用程序所在的路径。 

//获得从服务器端已下载文档的最近一次更新日期 
string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName); 
     theFolder.FullName指在升级文档下载到客户机上的临时文件夹所在的路径。 

4.3 比较日期 
   客户端应用程序最近一次更新日期与服务器端升级程序的最近一次更新日期进行比较。 
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->//获得已下载文档的最近一次更新日期 string theLastsUpdateDate = GetTheLastUpdateTime(theFolder.FullName); if(thePreUpdateDate != "") { //如果客户端将升级的应用程序的更新日期大于服务器端升级的应用程序的更新日期 if(Convert.ToDateTime(thePreUpdateDate)>=Convert.ToDateTime(theLastsUpdateDate)) { MessageBox.Show("当前软件已经是最新的,无需更新!","系统提示",MessageBoxButtons.OK,MessageBoxIcon.Information); this.Close(); } } this.labDownFile.Text = "下载更新文件"; this.labFileName.Refresh(); this.btnCancel.Enabled = true; this.progressBar.Position = 0; this.progressBarTotal.Position = 0; this.progressBarTotal.Refresh(); this.progressBar.Refresh(); //通过动态数组获取下载文件的列表 ArrayList List = GetDownFileList(GetTheUpdateURL(),theFolder.FullName); string[] urls = new string[List.Count]; List.CopyTo(urls, 0);
    将客户端升级的应用程序的日期与服务器端下载的应用程序日期进行比较,如果前者大于后者,则不更新;如果前者小于后者,则通过动态数组获取下载文件的列表,开始下载文件。
 通过BatchDownload()函数来实现。升级程序检测旧的主程序是否活动,若活动则关闭旧的主程序;删除旧的主程序,拷贝临时文件夹中的文件到相应的位置;检查主程序的状态,若状态为活动的,则启动新的主程序。
Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->private void BatchDownload(object data) { this.Invoke(this.activeStateChanger, new object[]{true, false}); try { DownloadInstructions instructions = (DownloadInstructions) data; //批量下载 using(BatchDownloader bDL = new BatchDownloader()) { bDL.CurrentProgressChanged += new DownloadProgressHandler(this.SingleProgressChanged); bDL.StateChanged += new DownloadProgressHandler(this.StateChanged); bDL.FileChanged += new DownloadProgressHandler(bDL_FileChanged); bDL.TotalProgressChanged += new DownloadProgressHandler(bDL_TotalProgressChanged); bDL.Download(instructions.URLs, instructions.Destination, (ManualResetEvent) this.cancelEvent); } } catch(Exception ex) { ShowErrorMessage(ex); } this.Invoke(this.activeStateChanger, new object[]{false, false}); this.labFileName.Text = ""; //更新程序 if(this._Update) { //关闭原有的应用程序 this.labDownFile.Text = "正在关闭程序...."; System.Diagnostics.Process[]proc=System.Diagnostics.Process.GetProcessesByName("TIMS"); //关闭原有应用程序的所有进程 foreach(System.Diagnostics.Process pro in proc) { pro.Kill(); } DirectoryInfo theFolder=new DirectoryInfo(Path.GetTempPath()+"JurassicUpdate"); if(theFolder.Exists) { foreach(FileInfo theFile in theFolder.GetFiles()) { //如果临时文件夹下存在与应用程序所在目录下的文件同名的文件,则删除应用程序目录下的文件 if(File.Exists(Application.StartupPath + \\"+Path.GetFileName(theFile.FullName))) File.Delete(Application.StartupPath + "\\"+Path.GetFileName(theFile.FullName)); //将临时文件夹的文件移到应用程序所在的目录下 File.Move(theFile.FullName,Application.StartupPath + \\"+Path.GetFileName(theFile.FullName)); } } //启动安装程序 this.labDownFile.Text = "正在启动程序...."; System.Diagnostics.Process.Start(Application.StartupPath + "\\" + "TIMS.exe"); this.Close(); } }
 这段程序是实现在线升级的关键代码,步骤有点复杂:首先用Invoke方法同步调用状态改变进程,然后调用动态链接库中批量下载(BatchDownloader.cs)类启动批量下载,接着判断原有的主应用程序有没有关闭,如果没关闭,则用Process.Kill()来关闭主程序。接下来,判断临时文件夹下(即下载升级程序所在的目录)是否存在与应用程序所在目录下的文件同名的文件,如果存在同名文件,则删除应用程序目录下的文件,然后将临时文件夹的文件移到应用程序所在的目录下。最后重新启动主应用程序。这样更新就完成了。
2009-07-20 13:18:00 jiangshaofen 阅读数 1298

操作近一年的MMS/PES系统将按计划在85进行第一轮用户测试,忙了很久的作业就要接受用户的考评,与往常项目一样,小有点兴奋。由于长时期不写C#代码,一直忙于C方面的东西,再次着手写C#具体代码的时候,总觉得有点生疏。所以趁着周日,写了此代码以做C#代码练习。

言归正传,大概描述下这个东西的实现思路:

    首先是服务器端,将要更新的文件上传到服务器端提供客户端下载,服务器端配置有更新文件的XML样式的配置文件—Libinfo.xml(此文件在客户端第一上传更新文件后在服务器端创建,以后再上传将会改写此文件)。其格式如下:

 

    其次是客户端,此程序集成在客户端,每次客户端启动前将会自动检测服务器端文件版本,若有新版本,客户端将自动下载更新本地相应之文件,之后再正式启动应用程序。这样客户端始终使用最新版本的文件。此方式不用考虑客户端程序在运行状态,以此来避免造成客户端业务数据因升级而丢失。另外客户端需要配置一个项目XML文件—Config.xml。格式如下:

(待续...)

 

2014-06-17 10:00:00 weixin_33725807 阅读数 3

实现功能:

  1. 设计程序,分别构建通信的两端:服务器端和客户端应用程序,套接字类型为面向连接的Socket,自己构建双方的应答模式,实现双方的数据的发送和接收(S发给CC发给S)。

  2. 服务端程序能响应单个或任意多个客户端连接请求;服务端能向单个客户发送消息,支持群发消息给所有客户端;

  3. 通信的双方具备异常响应功能,包括对方异常退出的处理。如果客户端退出,服务器有响应;反之亦然。

设计思路:

1.服务器设计思路:服务器的设计是这次实验最复杂的部分,因为服务器的功能比较多。作为服务器,它要可以同时与多个客户端连接,为每一个连接的客户端创建一个通信Socket,自己还要有一个Socket用于监听客户端的连接请求;服务器要创建一个数据结构用于保存连接进来的客户端的信息(Socket和客户端的名字);服务器要将连接进来的客户端显示出来,用户可以根据显示出来的用户列表来向指定的客户端发信息;服务器要能及时地刷新客户端列表,当有新的客户端连接进来或是退出的时候要及时通知所有的客户端并刷新自己的客户端列表;服务器要能接收所有的客户端的信息,并将信息无错地转发给指定的客户端。

2.客户端设计思路:客户端的设计相对于服务器来说的话对会比较简单一点。客户端要有接收服务器信息的功能,但客户端只向服务器发信息,客户端通过服务器的转发功能向其它的客户端发送信息。客户端要可以处理服务器发过来的信息,还要有数据结构用来保存所有客户端的名字,并将所有客户端名字列表显示出来。可以指定客户端列表里面的多个项来向不同的客户端发信息。

3.通信数据处理:无论是服务器发给客户端,还是客户端发给服务器的数据,方都要进行处理。对于不用的类型的数据要设计不用的标志信息,当双方收到信息后跟据标志信息进行不同的处理。数据可以分为三种:

       a)登陆信息。这类信息提示有新的客户端连接进来。该信息由客户端首先发给服务器,服务器收到后会更新自己的在线客户端列表,增加与该客户端通信的Socket和名字,并将该信息转发给所有在线的客户端,提醒客户端即时更新客户端列表。这类信息以“login,客户端名”的形式发送。

        b)退出信息。这类信息提示发信息的客户端即将退出服务器。该信息由客户端首先发给服务器,服务器收到后会更新自己的在线客户端列表,删除与该客户端通信的Socket和名字,并将该信息转发给所有在线的客户端,提醒客户端即时更新客户端列表。这类信息以“logout,客户端名”的形式发送。

       c)通信信息。这类信息提示发送信息的客户端向在线的某个客户端或是服务器发起了通信,也可以是服务器与某个客户端发起了通信。如果该信息是服务器发给客户端或是客户端发给服务器,则直接发送,不用经过转发;如果是客户端向另一个客户端发送信息,则是先发给服务器,服务再转发给指定的客户端。这类信息以“talk,目的客户端名,发送的信息”的形式发送。

4.线程的设计思路:在服务器方面,需要一个程专门用于监听客户端的连接请求,对于连接进来的每一个客户端,还要创建一个线程用于接收信息,程序的主线程用于向不同的客户端发送信息,所以服务器至少需要要n+2(n>=0)个线程;在客户端方面,需要一个线程用于接收服务的信息,还要一个线程用于向服务器发送信息,所以只需要2个线程。

5.信息无边界问题:由于这里用的C#里面原始Socket套接字,所以在数据收发的过程中会出现无边界的问题。有时服务器向客户端发送多条不同类型的信息,客户端会把它们合并在一起,当成一条信息处理。为了提取不同类型的信息,发送信息之前要为每一条信息加特定的结束符。

服务器处理不同类型信息代码:

string[] splitString = receiveString.Split(',');             //分割字符
                switch (splitString[0].ToLower())
                {
                    case  "login":                            // 登陆信息
                        user.username = splitString[1];
                        userList.Add (user);                  // 增加用户列表
                        AddItemToListBox (user.username);     // 刷新用户列表
                        sendToAllClient (user,receiveString); // 通知所有在线用户
                        FirstLogin (user);
                        break; 
                    case  "logout":                           // 退出信息
                        DeletItemInListBox (user.username);  
                        sendToAllClient (user,receiveString);// 通知所有在线用户 
                        RemoveUser (user);                   // 删除用户信息
                        UserCount (--usercount);             // 刷新用户列表
                        break; 
                    case  "talk":                            // 对话信息
                        multMessage (user,receiveString);    // 转发对话
                        break; 
                    default: 
                        sendMessageTorichBox ("不知道什么意思!");
                        break; 
                }

服务器监听客户端代码:

private  void button1_Click(object sender, EventArgs e)
        {
            isNormalExit  = false;
            buttu_richBoxDelegate  d = buttu_richBox;       // 委托事件
           try 
           {
            myListener.Listen (10);                          // 开始监听
               richTextBox1.Invoke(d,"成功监听.");           // 成功监听
 
           } catch{
               richTextBox1.Invoke(d,"监听失败。");         
           }
            Thread mhThread = new Thread(ListenClientConnect);  // 创建新的线程
            mhThread.IsBackground = true;                       // 设置为后台线程
            mhThread.Start ();
            button1.Enabled=false;                              // 开始监听按钮不可用
            button2.Enabled= true;                                
        }

服务器接受客户端代码:

private void ListenClientConnect ()
{
            Socket newClient =null;
            While (isNormalExit==false)
            {
try 
                {
                    newClient = myListener.Accept();          // 接受客户端
                    if(isNormalExit == true)                  // 如果服务器停止监听
                    { 
                        newClient.Close();                     // 关闭Socket
                        usercount = 0;
                        UserCount(usercount);
                        Break;
                    }
                 }Catch{
                    break;
                }
                User user = new User(newClient);                 // 保存客户端列表
                Thread threadReceive = new Thread(ReceiveData);  // 创建新的线程
                threadReceive.IsBackground=true;                 //设置为后台线程
                threadReceive.Start(user);                       // 开始线程
                 UserCount(++usercount);                         // 客户端人数加1
            }
        }

客户端连接服务器代码:

Private  void button1_Click(object sender, EventArgs e)
         {  
            button1.Enabled = false;
            client  = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                              //新建套接字
            AddrichTextBox1Massage d = sendrichTextBox1Massage;
            Try 
            {
                String  name = Dns.GetHostName();                     // 获得计算机的名字
                IPHostEntry me = Dns.GetHostEntry (name);             //获得计算机IP
                  foreach(IPAddress ips in me.AddressList)
                  {
                    Try { 
                        IPEndPoint ep = new  IPEndPoint(ips, 8889);  
                         client.Connect(new IPEndPoint(ips, 8889));      // 连接服务器
                         break;
                    }
                     catch
                    {//若获取的IP是vs6的话 
}
                  }
             client.Send(Encoding.UTF8.GetBytes("login," + textBox1.Text));//向服务器发信息
             Thread threadReceive = new Thread(new ThreadStart(ReceiveData));//创建新线程
             threadReceive.IsBackground = true;                           // 设置为后台线程
             threadReceive.Start();                                       //开始线程
           }

客户端接收服务器信息代码:

private void ReceiveData()
        {
            AddrichTextBox1Massage d = sendrichTextBox1Massage;
             int receiveLength;
             while(isExit==false)
             {
                 try{
                     receiveLength = client.Receive(result);             //开始接收信息
                     recieveMessage=Encoding.UTF8.GetString(result,0,receiveLength);
                }catch{
                     if (isExit == false){
                         richTextBox1.Invoke(d, "与服务器失去联系。"); 
                         client.Shutdown(SocketShutdown.Both);            // 关闭套接字
                         client.Close();
                        }
                        break;
                }
                 string[] splitString = recieveMessage.Split(',');         //处理信息
                 string command = splitString[0].ToLower();
                 switch(command) {
                     case "login":AddOnline(recieveMessage);               // 登陆信息
                                  break;
                     case "logout": RemoveUserName(splitString[1]);        // 退出信息
                                  break;
                     case "talk": richTextBox1.Invoke(d, "["+splitString[1] + "]对我说: " + splitString[2]);                         // 对话信息
                                  break;
                    default: richTextBox1.Invoke(d,"不知什么意思。"); 
                             break;
                } 
            }
               LostConnect();                                               //关闭连接
        }

程序运行效果

1 服务器运行界面:

094758_HNe9_1540055.png

2 有客户端连接进服务器:

094845_z0I1_1540055.png

 上图表示有3个客户端连接进了服务器。在线客户列表显示了连接进的客户端的名字,在线客

  户人数显示为3

3 服务器向客户端发送信息:

095007_3FwM_1540055.png

 服务器向在线客户列表里的2个客户同时发了信息,2个客户端收到了

 正确的信息

4 客户端的启动界面:

095101_zRSq_1540055.png

客户端自动生成用户的名字

5 客户端登陆的界面:

095140_oo51_1540055.png

客户端显示连接成功,并刷新在线用户列表

6 多个客户端连接服务器时的界面:

095231_4NhZ_1540055.png

当有多个客户端与服务器连接时,客户端会自动更新在线用户列表

7 客户端同时向服务器和其它客户端发信息:

095309_ZciN_1540055.png

客户端可以同时向服务器和多个客户端发送信息。

8 客户端退出时:

095358_1mZL_1540055.png

客户端退出时,服务器会知道退出的用户,并把该客户端移出列表,同时发信息通知其它的客

户端,使它们可以及时地更新用户列表。

9 服务器退出时:

095443_oDAo_1540055.png


转载于:https://my.oschina.net/u/1540055/blog/280448

c#获取路径 c/s

阅读数 33

CAS C# C/S

阅读数 3357

C#(C/s,B/s)md5加密

阅读数 617

C#(C/s,B/s)md5加密

阅读数 454

没有更多推荐了,返回首页