客户端程序自动更新(升级)的方式

from:https://blog.csdn.net/woaitingting1985/article/details/72954652

一、C/S自动更新原理

 C/S程序自动升级是一个很重要的功能,原理其实很简单,一般包含两个程序一个是主程序,也就是除了升级功能以外的程序,另一个就是升级程序,常见的360,金山安全卫士都是这样。

 主要包括以下几点:   1 比较版本  2下载文件  3更新文件 4启动主程序。但其中的需要注意的细节很多。 

    一般服务端会有一个配置文件包含最新更新的文件信息的配置文件,当然这些更新信息也可以存到数据库,或者其他地方。客户端(也就是需要更新的那部分程序)也有一个配置文件包含客户端版本信息,这些信息可以存到专门的一个配置文件中,或者是config文件中,没有一定的规定,可以根据实际设计。

   在客户端程序启动时,先启动更新程序通过比较本地版本和服务端最新的版本信息判断是否有新版本,如果有可以直接下载,下载完成替换成功后并更新客户端版本信息,启动主程序。

            缺点:如果更新速度由于更新的文件很大或者网速很慢,用户不得不等待很长时间,直到下载完成或者下载失败。

            优点:处理完成后,启动的直接就是更新后的程序。不会出现由于主程序在运行导致替换文件时提示文件在使用,不能替换之类的错误。

   另一种方法是, 在客户端段程序启动时,启动更新程序,但更新程序不做版本判断,到客户端更新目录下检查有没有下载的新版本,如果有就更新主程序并更新客户端版本信息,然后启动主程序,如果没有就直接启动主程序。由主程序判断是否有新版本,并在后台下载把文件放到客户端更新目录中,下载完成后,提示用户退出主程序,重新启动,在启动时由更新程序并更新客户端和客户端版本信息。    

            缺点:由于下载是在主程序的后台运行,可能会影响主程序的处理速度。

            优点:避免了由于下载导致用户长时间的等待。

1 比较版本

    比较依据:

    可以通过文件的最后修改时间,或者使用文件版本作为比较依据,使用文件最后修改时间显然不是标准的做法,但也没有错误,但需要注意日期的格式一定要统一,避免日  期格式不一致导致错误。可以使用Fileinfo类获取最后修改时间,注意时间应该取服务器时间,编译程序集的机器时间应该相同,否则可能导致混乱。

FIleInfo类官网参考

   使用文件版本作为标准,则每次修改时必须修改版本号,C#程序就是要修AssemblyInfo.cs文件中的内容了,多了一步,规范多了。Version类处理版本信息并比较。 

  1. Assembly thisAssem = Assembly.GetExecutingAssembly();  
  2.      AssemblyName thisAssemName = thisAssem.GetName();  
  3.      Version ver = thisAssemName.Version;  

Version类官网参考

  当然也有其他的方式,例如MD5校验值比较,文件大小比较,之类的方法。不过个人认为文件大小缺陷很明显,新版本文件就一定比旧文件大吗?不一定吧。重构是可能变小的。

当然如果考虑客户端有不同的版本,都需要升级到最新的版本,显然不同的版本对应的升级文件不同,会更复杂,比较的信息也更多。

   获取服务端版本信息:

    如果服务端的版本信息存在数据库,直接读取数据库,就可以获取。如果存在配置文件,则可以通过webservice方法获取,或者请求一个网页 通过Response.Write();的方式获取信息,当然这两种方式都要建立虚拟目录或者网站。

2下载文件

  存储位置:

     如果新版本的文件存在数据库,就直接读取数据库,不过这种方式个人不建议使用,例如更新文件很大时性能不是很好。

    存在固定虚拟目录的指定路径下,不失为一种好的方式,但客户端要下载,所以要注意一定要分配下载权限。

下载方式:

   直接向通过虚拟路径发出请求,下载文件,由于虚拟路径有下载权限,如果更新需要判断是否有权限,例如要交费后才能下载则不好处理。

  另一种方式是向一个网页发送请求,传递不同的查询字符串,网页 通过Response.BinaryWrite();的方式下载文件,则可以判断权限,当然麻烦一些是避免不了的。

下载文件代码

  1. Uri uri = new Uri(downFileUrl + localFileName);  
  2.               HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);  
  3.               request.Credentials = CredentialCache.DefaultCredentials;  
  4.               request.MaximumAutomaticRedirections = 4;  
  5.               localFileName = Path.GetFileName(localFileName);  
  6.               using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())  
  7.               {  
  8.                   Stream receiveStream = response.GetResponseStream();  
  9.                   string newPath = Path.Combine(tempFold, localFileName);  
  10.                   using (FileStream fs = new FileStream(newPath, FileMode.Create))  
  11.                   {  
  12.                       Byte[] buffer = new Byte[4096];  
  13.                       int bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  14.                       while (bytesRead > 0){  
  15.                           fs.Write(buffer, 0, bytesRead);  
  16.                           bytesRead = receiveStream.Read(buffer, 0, buffer.Length);  
  17.                       }  
  18.                   }  
  19.                   receiveStream.Close();  
  20.               }  

3更新文件

      更新类型:

     直接替换的,例如修改了bug,直接替换的。

     新增加的,例如新增加的功能做成了新的类库。

    需要删除的,例如有些功能由于重构或者使用了了新方法不需要的。

     需要执行的,例如写注册表,注册COM组件的。

     每一种处理方式都不一样,需要根据类型分开处理

     缺点:升级后,没办法取消升级,像windows的补丁程序可以安装,可以卸载的原理,目前还没有研究明白,希望知道的牛人指导。

    当然也可以简单的先卸载,再安装,对于配置文件之类的信息特殊处理一下也可以。

   当然如果考虑客户端有不同的版本,都需要升级到最新的版本,显然不同的版本对应的升级文件不同,会更复杂,但基本原理却不变。

4启动主程序

  主程序路径的获取:

   相对路径   主程序,更新程序,都使用相对路径,缺点是一旦相对路径确定后,后续的更新就不能更改这种目录关系。

  注册表  路径都存入注册表,需要时通过注册表交互,主程序写注册表,更新程序读取注册表,缺点是读写注册表需要权限,写的路径也要固定,后续的更新不能改变写在注册表中的位置,也就是注册表路径。

运行程序代码

 

  1. private static void RunFile(string dir, string localFileName){  
  2.           string info = "运行程序" + localFileName;  
  3.           try{  
  4.               if (File.Exists(Path.Combine(dir, localFileName))){  
  5.                   Process myProcess = new Process();  
  6.                   ProcessStartInfo psi = new ProcessStartInfo();  
  7.                   psi.FileName = localFileName;  
  8.                   psi.WorkingDirectory = dir;  
  9.                   psi.UseShellExecute = false;  
  10.                   psi.RedirectStandardError = true;  
  11.                   psi.CreateNoWindow = true;  
  12.                   psi.RedirectStandardOutput = true;  
  13.                   psi.WindowStyle = ProcessWindowStyle.Hidden;  
  14.                   myProcess.StartInfo = psi;  
  15.                   myProcess.Start();  
  16.   
  17.                   string error = myProcess.StandardError.ReadToEnd();  
  18.                   string output = myProcess.StandardOutput.ReadToEnd();  
  19.                   myProcess.WaitForExit();  
  20.                   myProcess.Close();  
  21.                   if (error != string.Empty){  
  22.                    Log.Write("StandardError:" + error);  
  23.                   }  
  24.                   if (output != string.Empty){  
  25.                       Log.Write("StandardOutput:" + output);  
  26.                   }  
  27.                   Log.LogProcessEnd(info);  
  28.               }  
  29.           }  
  30.           catch (Exception ex){  
  31.              Log.Write(info + "出错");  
  32.              Log.LogException(ex);  
  33.               throw ex;  
  34.           }  
  35.       }  
  36.   }  

二、使用HttpWebRequest自动更新客户端
更新客户端应用程序,对于采用Socket实现的,可以采用Socket从服务器端下载;对于其它方式, 一般可以采用以HttpWebRequest/WebClient的方式予以下载,但WebClient在下载的时候无法看到下载进度,因此,使用HttpWebRequest 下载文件,根据读取到的流长度,确定当前下载的数据量,以反应当前下载的进度。

    找了半天也没有找到在那儿可以上传文件,所以只好将文件上传到博客园。

下载地址:http://www.cnblogs.com/Files/bluedream/Update.rar

说明:

在客户端,用户实际运行的是更新程序,在更新程序检查完成后,再运行实际的客户端。当然,这个对用户是隐藏的。

1、DownloadFile.cs: 使用HttpWebRequest下载指定URL的文件

2、EventArgs.cs:委托及事件

3、FormUpdate.cs:下载时的UI处理

4、Global.cs和UpdateUtility.cs通用处理函数库

5、Client.cs:更新客户端的应用程序

6、Update文件:客户端更新配置文件,在更新时,应用程序先读取Update文件,然后根据Update文件中存储的远程服务器URL地址,读取远程更新文件,接着比较远程服务器配置文件与本地配置文件及本地文件相比较,确定更新列表,然后下载文件;下载完成后,覆盖本地文件;再删除临时文件;最后调用本地配置文件指定的更新完成后应运行的应用程序。


三、JAVA自动更新客户端

最近由于一个工程需要做应用程序启动时,自动更新的项目
在GOOGLE上找了半天也没见到什么比较好的办法
自己动手写了一个通过版本号检查网络上是不是存在新的更新文件,并自动通过HTTP下载文件的程序
希望对正在找此类程序的朋友有帮助

本地文件需要一个ver.txt  此文件内容为本地软件版本号
网络上我直接在一个页面上打印出网络存在的版本号
例如,这个例子里,我在 http://XXX.XXX.XXX/AutoUpdate/ver  这里直接打印出版本号

源文件:http://211.136.109.100/beiouwolf/AutoUpdate.rar

 

[java] view plaincopy
 
  1. import javax.swing.*;  
  2. import java.awt.*;  
  3. import java.net.*;  
  4. import java.io.*;  
  5.   
  6. public class CheckUpdate extends JFrame {  
  7.     JFrame c = this;  
  8.   
  9.     public CheckUpdate() {  
  10.         //设置窗体属性  
  11.         setAttb();  
  12.   
  13.         JLabel title = new JLabel("正在检查网络上的更新资源");  
  14.         this.add(title, BorderLayout.NORTH);  
  15.         JTextArea msg = new JTextArea();  
  16.         this.add(msg, BorderLayout.CENTER);  
  17.         JLabel process = new JLabel();  
  18.         this.add(process, BorderLayout.SOUTH);  
  19.           
  20.         //启动更新线程  
  21.         new Check(msg, process).start();  
  22.     }  
  23.   
  24.     private class Check extends Thread {  
  25.         //标识,是否存在新的更新文件  
  26.         private boolean isUpdated = false;  
  27.         //保存最新的版本  
  28.         String netVersion;  
  29.         //本地版本文件名  
  30.         String LocalVerFileName = "ver.txt";  
  31.   
  32.         //显示信息  
  33.         private JTextArea msg;  
  34.         private JLabel process;  
  35.   
  36.         public Check(JTextArea msg, JLabel process) {  
  37.             this.msg = msg;  
  38.             this.process = process;  
  39.         }  
  40.   
  41.         public void run() {  
  42.             //更新文件版本标识URL  
  43.             String versionUrl = "http://XXX.XXX.XXX/AutoUpdate/ver";  
  44.   
  45. /**//* 
  46. 这里是通过HTTP访问一个页面,以取得网络上的版本号 
  47. 比如这里就是在这个页面直接打印出 6.19.1.1 
  48. 然后把这个版本号比对本地的版本号,如果版本号不同的话,就从网络上下载新的程序并覆盖现有程序 
  49.  
  50. */  
  51.   
  52.             URL url = null;  
  53.             InputStream is = null;  
  54.             InputStreamReader isr = null;  
  55.             BufferedReader netVer = null;  
  56.   
  57.             //读取网络上的版本号  
  58.             try {  
  59.                 url = new URL(versionUrl);  
  60.                 is = url.openStream();  
  61.                 isr = new InputStreamReader(is);  
  62.   
  63.                 netVer = new BufferedReader(isr);  
  64.                 String netVerStr = netVer.readLine();  
  65.                 String localVerStr = getNowVer();  
  66.   
  67.                 if (netVerStr.equals(localVerStr)) {  
  68.                     msg.append("当前文件是最新版本\n");  
  69.                     isUpdated = false;  
  70.                 } else {  
  71.                     msg.append("存在更新文件,现在开始更新\n");  
  72.                     isUpdated = true;  
  73.                     netVersion = netVerStr;  
  74.                 }  
  75.   
  76.             } catch (MalformedURLException ex) {  
  77.             } catch (IOException ex) {  
  78.             } finally {  
  79.                 //释放资源  
  80.                 try {  
  81.                     netVer.close();  
  82.                     isr.close();  
  83.                     is.close();  
  84.                 } catch (IOException ex1) {  
  85.                 }  
  86.             }  
  87.   
  88.             //如果版本不同,下载网络上的文件,更新本地文件  
  89.             if (isUpdated) {  
  90.                 //本地需要被更新的文件  
  91.                 File oldFile = new File("client.exe");  
  92.                 //缓存网络上下载的文件  
  93.                 File newFile = new File("temp.exe");  
  94.                   
  95.                 //网络上的文件位置  
  96.                 String updateUrl =  
  97.                         "http://XXX.XXX.XXX/downloads/simpkle.exe";  
  98.   
  99.                 HttpURLConnection httpUrl = null;  
  100.                 BufferedInputStream bis = null;  
  101.                 FileOutputStream fos = null;  
  102.   
  103.                 try {  
  104.                     //打开URL通道  
  105.                     url = new URL(updateUrl);  
  106.                     httpUrl = (HttpURLConnection) url.openConnection();  
  107.   
  108.                     httpUrl.connect();  
  109.   
  110.                     byte[] buffer = new byte[1024];  
  111.   
  112.                     int size = 0;  
  113.   
  114.                     is = httpUrl.getInputStream();  
  115.                     bis = new BufferedInputStream(is);  
  116.                     fos = new FileOutputStream(newFile);  
  117.   
  118.                     msg.append("正在从网络上下载新的更新文件\n");  
  119.   
  120.                     //保存文件  
  121.                     try {  
  122.                         int flag = 0;  
  123.                         int flag2 = 0;  
  124.                         while ((size = bis.read(buffer)) != -1) {  
  125.                             //读取并刷新临时保存文件  
  126.                             fos.write(buffer, 0, size);  
  127.                             fos.flush();  
  128.   
  129.                             //模拟一个简单的进度条  
  130.                             if (flag2 == 99) {  
  131.                                 flag2 = 0;  
  132.                                 process.setText(process.getText() + ".");  
  133.                             }  
  134.                             flag2++;  
  135.                             flag++;  
  136.                             if (flag > 99 * 50) {  
  137.                                 flag = 0;  
  138.                                 process.setText("");  
  139.                             }  
  140.                         }  
  141.                     } catch (Exception ex4) {  
  142.                         System.out.println(ex4.getMessage());  
  143.                     }  
  144.   
  145.                     msg.append("\n文件下载完成\n");  
  146.   
  147.                     //把下载的临时文件替换原有文件  
  148.                     CopyFile(oldFile,newFile);  
  149.                       
  150.                     //把本地版本文件更新为网络同步  
  151.                     UpdateLocalVerFile();  
  152.   
  153.                 } catch (MalformedURLException ex2) {  
  154.                 } catch (IOException ex) {  
  155.                     msg.append("文件读取错误\n");  
  156.                 } finally {  
  157.                     try {  
  158.                         fos.close();  
  159.                         bis.close();  
  160.                         is.close();  
  161.                         httpUrl.disconnect();  
  162.                     } catch (IOException ex3) {  
  163.                     }  
  164.                 }  
  165.             }  
  166.   
  167.             //启动应用程序  
  168.             try {  
  169.                 msg.append("启动应用程序");  
  170.                 Thread.sleep(500);  
  171.                 Process p = Runtime.getRuntime().exec("client.exe");  
  172.             } catch (IOException ex5) {  
  173.             } catch (InterruptedException ex) {  
  174.             }  
  175.               
  176.             //退出更新程序  
  177.             System.exit(0);  
  178.         }  
  179. //复制文件  
  180.         private void CopyFile(File oldFile, File newFile) {  
  181.             FileInputStream in = null;  
  182.             FileOutputStream out = null;  
  183.               
  184.             try {  
  185.                 if(oldFile.exists()){  
  186.                     oldFile.delete();  
  187.                 }  
  188.                 in = new FileInputStream(newFile);  
  189.                 out = new FileOutputStream(oldFile);  
  190.   
  191.                 byte[] buffer = new byte[1024 * 5];  
  192.                 int size;  
  193.                 while ((size = in.read(buffer)) != -1) {  
  194.                     out.write(buffer, 0, size);  
  195.                     out.flush();  
  196.                 }  
  197.             } catch (FileNotFoundException ex) {  
  198.             } catch (IOException ex) {  
  199.             } finally {  
  200.                 try {  
  201.                     out.close();  
  202.                     in.close();  
  203.                 } catch (IOException ex1) {  
  204.                 }  
  205.             }  
  206.   
  207.         }  
  208.   
  209.         private void UpdateLocalVerFile() {  
  210.             //把本地版本文件更新为网络同步  
  211.             FileWriter verOS = null;  
  212.             BufferedWriter bw = null;  
  213.             try {  
  214.                 verOS = new FileWriter(LocalVerFileName);  
  215.   
  216.                 bw = new BufferedWriter(verOS);  
  217.                 bw.write(netVersion);  
  218.                 bw.flush();  
  219.   
  220.             } catch (IOException ex) {  
  221.             } finally {  
  222.                 try {  
  223.                     bw.close();  
  224.                     verOS.close();  
  225.                 } catch (IOException ex1) {  
  226.                 }  
  227.             }  
  228.         }  
  229.   
  230.         private String getNowVer() {  
  231.             //本地版本文件  
  232.             File verFile = new File(LocalVerFileName);  
  233.   
  234.             FileReader is = null;  
  235.             BufferedReader br = null;  
  236.   
  237.             //读取本地版本  
  238.             try {  
  239.                 is = new FileReader(verFile);  
  240.   
  241.                 br = new BufferedReader(is);  
  242.                 String ver = br.readLine();  
  243.   
  244.                 return ver;  
  245.             } catch (FileNotFoundException ex) {  
  246.                 msg.append("本地版本文件未找到\n");  
  247.             } catch (IOException ex) {  
  248.                 msg.append("本地版本文件读取错误\n");  
  249.             } finally {  
  250.                 //释放资源  
  251.                 try {  
  252.                     br.close();  
  253.                     is.close();  
  254.                 } catch (IOException ex1) {  
  255.                 }  
  256.             }  
  257.             return "";  
  258.         }  
  259.     }  
  260.   
  261.   
  262.     private void setAttb() {  
  263.         //窗体设置  
  264.         this.setTitle("Auto Update");  
  265.         this.setSize(200150);  
  266.         this.setLayout(new BorderLayout());  
  267.         this.setDefaultCloseOperation(EXIT_ON_CLOSE);  
  268.   
  269.         // 窗体居中  
  270.         Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();  
  271.         Dimension frameSize = this.getSize();  
  272.         if (frameSize.height > screenSize.height) {  
  273.             frameSize.height = screenSize.height;  
  274.         }  
  275.         if (frameSize.width > screenSize.width) {  
  276.             frameSize.width = screenSize.width;  
  277.         }  
  278.         this.setLocation((screenSize.width - frameSize.width) / 2,  
  279.                          (screenSize.height - frameSize.height) / 2);  
  280.     }  
  281.   
  282.     public static void main(String[] args) {  
  283.         CheckUpdate checkupdate = new CheckUpdate();  
  284.         checkupdate.setVisible(true);  
  285.     }  
  286. }  


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/woaitingting1985/article/details/72954652

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458283.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎么用源程序把ChemDraw结构复制到Word文档

在学习化学过程中,不可避免的会接触到各种化学结构。这个时候就需要通过绘制化学结构来进行这方面的学习和传播。ChemDraw Professional 15就可以辅助完成这方面的工作。很多的用户朋友会通过选中后复制粘贴可以将ChemDraw结构复制到Word文档中,但这只是…

QT串口编程的相关类(QSerialPortInfo)

QT Serial Port相关的类只有两个QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先来介绍QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 该类是一个串口的辅助类类&#xff0c;提供主要是提…

用jquery写一个属于自己的音乐播放器

看到一个用css3实现的CD的动画&#xff0c;演示在这儿http://codepen.io/_kieran/pen/QNRmep 突然那我就想说给自己做一个音乐播放器吧&#xff0c;说做就做。演示在https://echolsx.github.io/music/ Github传送门&#xff1a;https://github.com/EchoLsx/music 主要代码&…

MySQL 性能监控 4 大指标

【编者按】本文作者为 John Matson&#xff0c;主要介绍 mysql 性能监控应该关注的 4 大指标。 文章系国内 ITOM 管理平台 OneAPM 编译呈现。 MySQL 是什么&#xff1f; MySQL 是现而今最流行的开源关系型数据库服务器。由 Oracle 所有&#xff0c;MySQL 提供了可以免费下载的社…

【深度相机系列四】深度相机原理揭秘--结构光(iPhone X 齐刘海原理)

from&#xff1a;https://blog.csdn.net/electech6/article/details/78707839导读 结构光法&#xff1a;为解决双目匹配问题而生 深度图效果&#xff1a;结构光vs.双目 投射图案的编码方式直接编码时分复用编码空分复用编码 Kinect1原理 iPhone X原深感相机是缩小版的更强大的K…

Android倒计时工具类

为什么80%的码农都做不了架构师&#xff1f;>>> 原文地址:http://my.oschina.net/reone/blog/710003 多谢touch_ping 的回应. 原来api有这个类 android.os.CountDownTimer , 具体实现很下面的差不多. import android.content.Context; import android.os.Handler…

深度相机原理揭秘--双目立体视觉

欢迎关注计算机视觉life&#xff01;导读 为什么非得用双目相机才能得到深度&#xff1f; 双目立体视觉深度相机的工作流程 双目立体视觉深度相机详细工作原理理想双目相机成像模型极线约束图像矫正技术基于滑动窗口的图像匹配基于能量优化的图像匹配 双目立体视觉深度相机的优…

微信扫码支付模式一和模式二的区别

http://www.baidu.com/link?urlAj_xhOM5Q6rpZXkTMBPq4o0UbCO4eLq0esX8B3K2v06bkRS8F8lC4k06rv-3uZARLLTEKJHMhwzI_cdcJiHfqK&wd&eqid904bc71f000181740000000356d7d9bf https://www.zhihu.com/question/35818812/answer/66086727 知乎页面访问存在502 Bad Gateway问题…

双目视觉几何框架详解(玉米专栏8篇汇总)

一、图像坐标&#xff1a;我想和世界坐标谈谈(A) 玉米竭力用轻松具体的描述来讲述双目三维重建中的一些数学问题。希望这样的方式让大家以一个轻松的心态阅读玉米的《计算机视觉学习笔记》双目视觉数学架构系列博客。这个系列博客旨在捋顺一下已标定的双目视觉中的数学主线。数…

(原)Ubuntu14中安装GraphicsMagick

转载请注明出处&#xff1a; http://www.cnblogs.com/darkknightzh/p/5661439.html 参考网址&#xff1a; http://comments.gmane.org/gmane.comp.video.graphicsmagick.core/514 http://www.graphicsmagick.org/INSTALL-unix.html https://github.com/clementfarabet/graphics…

世界坐标系和相机坐标系,图像坐标系的关系

from&#xff1a;https://blog.csdn.net/waeceo/article/details/50580607一、四个坐标系简介和转换相机模型为以后一切标定算法的关键&#xff0c;只有这边有相当透彻的理解&#xff0c;对以后的标定算法才能有更好的理解。本人研究了好长时间&#xff0c;几乎每天都重复看几遍…

PythonOCC 3D图形库学习—创建立方体模型

Open CASCADE&#xff08;简称OCC&#xff09;平台是是一个开源的C类库&#xff0c;OCC主要用于开发二维和三维几何建模应用程序&#xff0c;包括通用的或专业的计算机辅助设计CAD系统、制造或分析领域的应用程序、仿真应用程序或图形演示工具。 PythonOCC是对Open CASCADE的封…

Struts2、SpringMVC、Servlet(Jsp)性能对比 测试 。 Servlet的性能应该是最好的,可以做为参考基准,其它测试都要向它看齐,参照...

2019独角兽企业重金招聘Python工程师标准>>> Struts2、SpringMVC、Servlet(Jsp)性能对比 测试 。 Servlet的性能应该是最好的&#xff0c;可以做为参考基准&#xff0c;其它测试都要向它看齐&#xff0c;参照它。 做为一个程序员&#xff0c;对于各个框架的性能要有…

基于图像分割的立体匹配方法

1.绪论 立体匹配是三维重建系统的关键步骤&#xff0c;并且作为一种非接触测量方法在工业以及科研领域具有重要的应用价值。为了完成匹配工作以及获取场景的稠密视差图&#xff0c;可以通过构建能量函数对应立体匹配的约束条件。复杂能量函数的全局最优解通常是NP难问题。相对于…

深度相机(二)--结构光深度测距

原文&#xff1a; http://blog.sina.com.cn/s/blog_80ce3a550100wg5j.html http://blog.csdn.net/u013360881/article/details/51395427 网上资源&#xff1a;http://eia.udg.es/~qsalvi/recerca.html 结构光编码&#xff1a; 在3D 的深度获取上&#xff0c;最为常见的方法是类…

用python实现模拟登录人人网

用python实现模拟登录人人网 字数4068 阅读1762 评论19 喜欢46我决定从头说起。懂的人可以快速略过前面理论看最后几张图。 web基础知识 从OSI参考模型&#xff08;从低到高&#xff1a;物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0c;传输层&#xff0c;会话层&a…

双目相机--双目视差与深度距离关系推导详解

相机成像的模型如下图所示&#xff1a; P为空间中的点&#xff0c;P1和P2是点P在左右像平面上的成像点&#xff0c;f是焦距&#xff0c;OR和OT是左右相机的光心。由下图可见左右两个相机的光轴是平行的。XR和XT是两个成像点在左右两个像面上距离图像左边缘的距离。 -----------…

SQL Server有这些属性吗

2019独角兽企业重金招聘Python工程师标准>>> Navicat for SQL Server是一个全面的图形化方式管理数据库&#xff0c;可进行创建、编辑和删除全部数据库对象&#xff0c;例如表、视图、函数、索引和触发器&#xff0c;或运行SQL查询和脚本&#xff0c;查看或编辑BLOB…

【立体视觉】双目立体标定与立体校正

from&#xff1a;https://blog.csdn.net/u011574296/article/details/73826420 参考&#xff1a; 机器视觉学习笔记&#xff08;6&#xff09;——双目摄像机标定参数说明 机器视觉学习笔记&#xff08;8&#xff09;——基于OpenCV的Bouguet立体校正 双摄像头立体成像(三)-畸变…

bootstrap .col-md-6 文字居中问题处理

转载于:https://www.cnblogs.com/benbenfishfish/p/5672520.html