简介:

Webbech能测试处在相同硬件上,不同服务的性能以及不同硬件上同一个服务的运行状况.webBech的标准测试可以向我们展示服务器的两项 内容:每秒钟相应请求数和每秒钟传输数据量.webbench不但能具有便准静态页面的测试能力,还能对动态页面(ASP,PHP,JAVA,CGI)进 行测试的能力.还有就是他支持对含有SSL的安全网站例如电子商务网站进行静态或动态的性能测试.

×××××××××××××××××××××××××吐槽,可忽略××××××××××××××××××××××

 好吧 , 我承认好高端,但整个代码也就几百行,还是算上注释呀,看完之后,完全没有什么动态网页测试,SSL 安全网站测试什么选项呀!!!!

,只有选择http协议的请求头选项呀,什么GET,HEAD,之类的

×××××××××××××××××××××××××××××××××××××××××××××××××××××

了解代码,你先得了解它的业务流程

 难点一:获取web服务器信息

     解决这个问题,首先你的了解你要测试什么? 你要测试的是一个web服务器应对大量请求的能力,就是所说的压力测试。你要做的是同时构造大量的请求,达到测试目的。

     请求是由 URL 地址连接 指示的,你要明白URL 地址连接由什么组成,你需要从其中获取那些必要的信息构成请求。url的一般模式为

    http://myname:mypass@www.vimer.cn:80/mydir/myfile.html?myvar=myvalue#myfrag

      

URI部分

意义

http

协议名称

myname

用户名(可选)

mypass

密码(可选)

www.vimer.cn

主机网络地址

80

端口号(可选)

/mydir/myfile.html

资源路径

myvar=myvalue

查询字符串(可选)

myfrag

锚点(可选)

  要从url 提取 host 和 request ,host是主机网络地址,reques 是利用http请求头和资源路径构成的一个http协议请求,web服务器会处理这个请求并且返回资源,一个例子:

    输入: http://www.vimer.cn/2010/02/%e7%ae%80%e6%98%8ehttp%e5%8d%8f%e8%ae%ae.html
    host  www.vimer.cn request  GET /2010/02/%e7%ae%80%e6%98%8ehttp%e5%8d%8f%e8%ae%ae.html HTTP/1.0

如果你纵览了代码,可以说60%的功能都用来进行字符串操作,来获得 hostrequest  不无论是mian函数还build_request 都是来实现这个功能的。具体的细节实现可以参考代码注释,注意一下,使用了大量的字符串函数,随时要准备man一下。

难点二:如何测评,依据是什么

测试就的有一个标准,webbench的标准是成功使用stock建立的http链接,benchwork函数做的就是这样一项工作。webbench使用的是多进程操作,

它选用了通道作为parent和childern的联系方式,来告知parent,child成功或失败建立了几个连接,传送的总的字节数是多少。在博文的最后有一个benchwork函数的流程图,有兴趣的可以看一下

代码

webbench.c

  1 /*
  2  * (C) Radim Kolar 1997-2004
  3  * This is free software, see GNU Public License version 2 for
  4  * details.
  5  *
  6  * Simple forking WWW Server benchmark:
  7  *
  8  * Usage:
  9  *   webbench --help
 10  *
 11  * Return codes:
 12  *    0 - sucess
 13  *    1 - benchmark failed (server is not on-line)
 14  *    2 - bad param
 15  *    3 - internal error, fork failed
 16  *
 17  */
 18 #include "socket.c"
 19 #include <unistd.h>
 20 #include <sys/param.h> //描述系统参数
 21 #include <rpc/types.h>
 22 #include <getopt.h>//参数分析
 23 #include <strings.h>
 24 #include <time.h>
 25 #include <signal.h>//信号处理
 26
 27 /* values */
 28 volatile int timerexpired=0;
 29 /*  volatile
 30  *  提示编译器所定义的变量随时可能改变,因此编译后的程序每次需要存储或是i
 31  *  读取该变量的时候,都会直接从变量地址读取数据。
 32  *  之所以要这样做,是因为编译器会对代码的读取和存储进行优化,可能暂时使用
 33  *  寄存器的值。
 34  * */
 35 int speed=0;
 36 int failed=0;
 37 int bytes=0;
 38 /* globals */
 39 int http10=1; /* 0 - http/0.9, 1 - http/1.0, 2 - http/1.1 */
 40 /* Allow: GET, HEAD, OPTIONS, TRACE */
 41 #define METHOD_GET 0
 42 #define METHOD_HEAD 1
 43 #define METHOD_OPTIONS 2
 44 #define METHOD_TRACE 3
 45 #define PROGRAM_VERSION "1.5"
 46 int method=METHOD_GET;
 47 int clients=1;/* 测试进程数,默认1:w*/
 48 int force=0;/* 等待服务器返回标志 ,默认为等待返回 0 */
 49 int force_reload=0;
 50 int proxyport=80;/* 服务器端口号,http协议默认为80端口*/
 51 char *proxyhost=NULL;//代理服务器
 52 int benchtime=30;/* 运行时间,默认为30 */
 53 /* internal */
 54 int mypipe[2];                    /* 通道 */
 55 char host[MAXHOSTNAMELEN];/* 域名 */
 56 #define REQUEST_SIZE 2048
 57 char request[REQUEST_SIZE];/* http 请求头 */
 58
 59 static const struct option long_options[]=
 60 {
 61  {"force",no_argument,&force,1},
 62  {"reload",no_argument,&force_reload,1},
 63  {"time",required_argument,NULL,'t'},
 64  {"help",no_argument,NULL,'?'},
 65  {"http09",no_argument,NULL,'9'},
 66  {"http10",no_argument,NULL,'1'},
 67  {"http11",no_argument,NULL,'2'},
 68  {"get",no_argument,&method,METHOD_GET},
 69  {"head",no_argument,&method,METHOD_HEAD},
 70  {"options",no_argument,&method,METHOD_OPTIONS},
 71  {"trace",no_argument,&method,METHOD_TRACE},
 72  {"version",no_argument,NULL,'V'},
 73  {"proxy",required_argument,NULL,'p'},
 74  {"clients",required_argument,NULL,'c'},
 75  {NULL,0,NULL,0}
 76 };
 77 /*  静态函数
 78  *  特性:
 79  *  1.周期:整个程序,范围:本文件
 80  *  2.使用static作为前缀,仅可以本文件函数调用,
 81  *  不能被同一程序的其他文件调用
 82  *  3.可以在不同文件里使用相同的函数名,不用担心冲突
 83  * */
 84 /* prototypes */
 85 static void benchcore(const char* host,const int port, const char *request);
 86 /* 测试 host 的连接 功能函数 */
 87 static int bench(void);
 88 /* 测试 host 的前期准备 和 多进程操作与同行 */
 89 static void build_request(const char *url);
 90 /* 解析 request */
 91
 92 static void alarm_handler(int signal)
 93 /* 和sig 和signaction 构成一个时钟 */
 94 {
 95    timerexpired=1;
 96 }
 97
 98 static void usage(void)
 99 /* 帮助 */
100 {
101    fprintf(stderr,
102     "webbench [option]... URL\n"
103     "  -f|--force               Don't wait for reply from server.\n"
104     "  -r|--reload              Send reload request - Pragma: no-cache.\n"
105     "  -t|--time <sec>          Run benchmark for <sec> seconds. Default 30.\n"
106     "  -p|--proxy <server:port> Use proxy server for request.\n"
107     "  -c|--clients <n>         Run <n> HTTP clients at once. Default one.\n"
108     "  -9|--http09              Use HTTP/0.9 style requests.\n"
109     "  -1|--http10              Use HTTP/1.0 protocol.\n"
110     "  -2|--http11              Use HTTP/1.1 protocol.\n"
111     "  --get                    Use GET request method.\n"
112     "  --head                   Use HEAD request method.\n"
113     "  --options                Use OPTIONS request method.\n"
114     "  --trace                  Use TRACE request method.\n"
115     "  -?|-h|--help             This information.\n"
116     "  -V|--version             Display program version.\n"
117     );
118 };
119 int main(int argc, char *argv[])
120 {
121  int opt=0;
122  int options_index=0;
123  char *tmp=NULL;
124
125  if(argc==1)
126  {
127       usage();
128           return 2;
129  }
130
131  while((opt=getopt_long(argc,argv,"912Vfrt:p:c:?h",long_options,&options_index))!=EOF )
132 /* 使用getopt 函数 获取分析命令,对一些参数进行设置 */
133  {
134   switch(opt)
135   {
136    case  0 : break;
137    case 'f': force=1;break;//Don't wait for reply from server
138    case 'r': force_reload=1;break;//Send reload request - Pragma: no-cache
139    case '9': http10=0;break;
140    case '1': http10=1;break;
141    case '2': http10=2;break;
142    case 'V': printf(PROGRAM_VERSION"\n");exit(0);
143    case 't': benchtime=atoi(optarg);break;//optarg[ getopt的全局变量 ] : 指向当前选项参数的指针
144    case 'p':
145           /* proxy server parsing server:port */
146          tmp=strrchr(optarg,':');
147              /*  char * strrchr(const char * s,int c )
148               *  返回 字符c 在字符串s末次出现的位置【返回值指向的是'c'
149               * */
150              /* 返回的是端口号
151               * */
152          proxyhost=optarg;
153          if(tmp==NULL)
154          {
155              break;
156          }
157          if(tmp==optarg)
158          {
159              fprintf(stderr,"Error in option --proxy %s: Missing hostname.\n",optarg);
160              return 2;
161          }//只有 :port
162          if(tmp==optarg+strlen(optarg)-1)
163          {
164              fprintf(stderr,"Error in option --proxy %s Port number is missing.\n",optarg);
165              return 2;
166          }//只有 server:
167          *tmp='\0';
168          proxyport=atoi(tmp+1);break;//获取端口号
169    case ':':
170    case 'h':
171    case '?': usage();return 2;break;
172    case 'c': clients=atoi(optarg);break;
173   }
174  }
175
176  if(optind==argc) {
177          /* optind getopt_long 函数的全局变量 ,表示下一个要解析的参数的位置
178           * 初始值为 1
179
180             可以这么理解:
181             如果一个程序有一个参数是必须需要的,则optind < argv,例如 webbench需要一个测试
182             目标URL,那么 webbench 会占用  0 的下标,而optind 已经默认初始化为1,可以预见
183             参数和参数的选项都会被getopt()操作后,optind 会指向下一个下标[无论是否存在],
184             不存在的话, optind就会和 argc 相等,相当于只输入了一个webbench ,
185             optind == argc == 1 ,
186           * */
187                       fprintf(stderr,"webbench: Missing URL!\n");
188               usage();
189               return 2;
190                     }
191
192  if(clients==0) clients=1;
193  if(benchtime==0) benchtime=60;
194  /* Copyright */
195  fprintf(stderr,"Webbench - Simple Web Benchmark "PROGRAM_VERSION"\n"
196      "Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.\n"
197      );
198  build_request(argv[optind]);
199  /* print bench info */
200  printf("\nBenchmarking: ");
201  switch(method)
202  {
203      case METHOD_GET:
204      default:
205          printf("GET");break;
206      case METHOD_OPTIONS:
207          printf("OPTIONS");break;
208      case METHOD_HEAD:
209          printf("HEAD");break;
210      case METHOD_TRACE:
211          printf("TRACE");break;
212  }
213 // printf(" %s",argv[optind]);
214  switch(http10)
215  {
216      case 0: printf(" (using HTTP/0.9)");break;
217      case 2: printf(" (using HTTP/1.1)");break;
218  }
219  printf("\n");
220  if(clients==1) printf("1 client");
221  else
222    printf("%d clients",clients);
223
224  printf(", running %d sec", benchtime);
225  if(force) printf(", early socket close");
226  if(proxyhost!=NULL) printf(", via proxy server %s:%d",proxyhost,proxyport);
227  if(force_reload) printf(", forcing reload");
228  printf(".\n");
229  return bench();
230 }
231
232 void build_request(const char *url)
233 {
234   char tmp[10];
235   int i;
236
237   bzero(host,MAXHOSTNAMELEN);
238   bzero(request,REQUEST_SIZE);
239   /* 初始化空间为0 */
240
241   if(force_reload && proxyhost!=NULL && http10<1) http10=1;
242   if(method==METHOD_HEAD && http10<1) http10=1;
243   if(method==METHOD_OPTIONS && http10<2) http10=2;
244   if(method==METHOD_TRACE && http10<2) http10=2;
245   /* 不知所以 ,缺少fftp的基本的基本知识 */
246
247   switch(method)
248   {
249       default:
250       case METHOD_GET: strcpy(request,"GET");break;
251       case METHOD_HEAD: strcpy(request,"HEAD");break;
252       case METHOD_OPTIONS: strcpy(request,"OPTIONS");break;
253       case METHOD_TRACE: strcpy(request,"TRACE");break;
254   }
255
256   strcat(request," ");
257
258   if(NULL==strstr(url,"://"))
259   {
260       fprintf(stderr, "\n%s: is not a valid URL.\n",url);
261       exit(2);
262   }
263   if(strlen(url)>1500)
264   {
265          fprintf(stderr,"URL is too long.\n");
266      exit(2);
267   }
268   if(proxyhost==NULL)
269        if (0!=strncasecmp("http://",url,7))
270                    /* int strncasecmp(char *s1,char *s2,int i)
271                     * 只比较s1的前 i 位和 s2的关系
272                     * */
273        { fprintf(stderr,"\nOnly HTTP protocol is directly supported, set --proxy for others.\n");
274              exit(2);
275            }
276   /* protocol/host delimiter */
277   i=strstr(url,"://")-url+3;
278   //printf("strstr(url,""): %p, url :%p, i = %d  \n",strstr(url,"://"),url,i);
279   /*  根据 数组在内存中存放的形式, 可以利用 strstr(..) 求的地址A,同时利用 url的
280    *  地址 B, A-B = 4[ 从低位开始放,就像压栈一样 ],
281    *  最后的 i 表示 一个http网址中, :// 之后的第一字符的下标
282    *  例如: http;//www.yankanshu.com .i 表示 w的下标位置
283    * */
284
285   if(strchr(url+i,'/')==NULL) {
286                                 fprintf(stderr,"\nInvalid URL syntax - hostname don't ends with '/'.\n");
287                                 exit(2);
288                               }
289   if(proxyhost==NULL)
290   {
291    /* get port from hostname */
292    if(index(url+i,':')!=NULL &&
293       index(url+i,':')<index(url+i,'/'))
294    {
295     //       printf("test 1\n ");
296        strncpy(host,url+i,strchr(url+i,':')-url-i);
297        bzero(tmp,10);
298        strncpy(tmp,index(url+i,':')+1,strchr(url+i,'/')-index(url+i,':')-1);
299        /* printf("tmp=%s\n",tmp); */
300        proxyport=atoi(tmp);
301        if(proxyport==0) proxyport=80;
302    } else
303    {
304   //   printf("test 2\n ");
305      strncpy(host,url+i,strcspn(url+i,"/"));
306    }
307   // printf("Host=%s\n",host);
308    /* 最后的host 是不带 http: 和 最后的 \
309     * 例如: http://baike.baidu.com/
310     * host = baike.baidu.com
311     * */
312    strcat(request+strlen(request),url+i+strcspn(url+i,"/"));
313    /*没有理解目的 :
314     * 根据测试:
315     *  GET 变成了 GET /.....*/
316   } else
317   {
318    // printf("ProxyHost=%s\nProxyPort=%d\n",proxyhost,proxyport);
319    strcat(request,url);
320   }
321   if(http10==1)
322       strcat(request," HTTP/1.0");
323   else if (http10==2)
324       strcat(request," HTTP/1.1");
325   strcat(request,"\r\n");
326   if(http10>0)
327       strcat(request,"User-Agent: WebBench "PROGRAM_VERSION"\r\n");
328           /*  字符串组合技巧
329            * */
330   if(proxyhost==NULL && http10>0)
331   {
332       strcat(request,"Host: ");
333       strcat(request,host);
334       strcat(request,"\r\n");
335   }
336   if(force_reload && proxyhost!=NULL)
337   {
338       strcat(request,"Pragma: no-cache\r\n");
339   }
340   if(http10>1)
341       strcat(request,"Connection: close\r\n");
342   /* add empty line at end */
343   if(http10>0) strcat(request,"\r\n");
344   // printf("Req=%s\n",request);
345 }
346
347 /* vraci system rc error kod */
348 static int bench(void)
349 {
350   int i,j,k;
351   pid_t pid=0;
352   FILE *f;
353
354   /* check avaibility of target server */
355  // printf("commmd: proxyhost= host %s proxhost %s\n",host,proxyhost);
356   i=Socket(proxyhost==NULL?host:proxyhost,proxyport);
357   //printf("commd: test3\n");
358
359   /*  建立测试网址的套接字
360    *  可以后的host的直接使用host
361    *  不可以的利用gethostbyname函数通过域名解析获得host
362    * */
363   if(i<0) {
364        fprintf(stderr,"\nConnect to server failed. Aborting benchmark.\n");
365            return 1;
366          }
367   close(i);
368   /* create pipe */
369   if(pipe(mypipe))
370           /* 进程间的通信方式
371            * 通道
372            * */
373   {
374       perror("pipe failed.");
375       return 3;
376   }
377
378   /* not needed, since we have alarm() in childrens */
379   /* wait 4 next system clock tick */
380   /*
381   cas=time(NULL);
382   while(time(NULL)==cas)
383         sched_yield();
384   */
385
386   /* fork childs */
387   for(i=0;i<clients;i++)
388   {
389        pid=fork();
390        if(pid <= (pid_t) 0)// 为了防止什么 ????
391        {
392            /* child process or error*/
393                sleep(1); /* make childs faster */
394            break;
395        }
396   }
397
398   if( pid< (pid_t) 0)
399   {
400           fprintf(stderr,"problems forking worker no. %d\n",i);
401       perror("fork failed.");
402       return 3;
403   }
404
405   if(pid== (pid_t) 0)
406   {
407     printf("commnd:request:%s\n",request);
408     /* I am a child */
409     if(proxyhost==NULL)
410       benchcore(host,proxyport,request);
411          else
412       benchcore(proxyhost,proxyport,request);
413
414          /* write results to pipe */
415      f=fdopen(mypipe[1],"w");
416      if(f==NULL)
417      {
418          perror("open pipe for writing failed.");
419          return 3;
420      }
421      /* fprintf(stderr,"Child - %d %d\n",speed,failed); */
422      fprintf(f,"%d %d %d\n",speed,failed,bytes);
423      fclose(f);
424      return 0;
425   } else
426   {
427       f=fdopen(mypipe[0],"r");
428       if(f==NULL)
429       {
430           perror("open pipe for reading failed.");
431           return 3;
432       }
433           /*  作为一个读的文件流,为什么要设置成 nobuf ????
434            * */
435       setvbuf(f,NULL,_IONBF,0);
436       speed=0;
437           failed=0;
438           bytes=0;
439
440       while(1)
441       {
442           pid=fscanf(f,"%d %d %d",&i,&j,&k);
443           if(pid<2)
444                   {
445                        fprintf(stderr,"Some of our childrens died.\n");
446                        break;
447                   }
448           speed+=i;
449           failed+=j;
450           bytes+=k;
451           /* fprintf(stderr,"*Knock* %d %d read=%d\n",speed,failed,pid); */
452           if(--clients==0) break;
453       }
454       fclose(f);
455
456   printf("\nSpeed=%d pages/min, %d bytes/sec.\nRequests: %d susceed, %d failed.\n",
457           (int)((speed+failed)/(benchtime/60.0f)),
458           (int)(bytes/(float)benchtime),
459           speed,
460           failed);
461   }
462   return i;
463 }
464
465 void benchcore(const char *host,const int port,const char *req)
466 {
467  int rlen;
468  char buf[1500];
469  int s,i;
470  struct sigaction sa;
471
472  /* setup alarm signal handler */
473  sa.sa_handler=alarm_handler;
474  sa.sa_flags=0;
475  if(sigaction(SIGALRM,&sa,NULL))
476          /* SIGALRM 是 定时器终止时发送给进程的信号
477           * SIG 是信号名的通用前缀,ALRM是alarm的缩写
478           * 通常作为长时间操作的超时信号
479           * 或者提供一种隔一定时间处理某些操作的方式
480           * 一般是在调用 alarm(t ) t秒后出现
481           * */
482     exit(3);
483  alarm(benchtime);
484  /* sigcation 和 alarm 设置了一个闹钟,用来定时退出 */
485
486  rlen=strlen(req);
487  nexttry:while(1)
488  {
489     if(timerexpired)
490     {
491        if(failed>0)
492        {
493           /* fprintf(stderr,"Correcting failed by signal\n"); */
494           failed--;
495        }
496        return;
497     }
498     s=Socket(host,port);
499     if(s<0) { failed++;continue;}
500     /*  申请建立连接失败, fail++
501      * */
502     if(rlen!=write(s,req,rlen)) {failed++;close(s);continue;}
503     /* 无法写入套接字,算是失败吧 ????
504      * fail++
505      * */
506     if(http10==0)
507             /*http 0.9 进行关闭操作 ????*/
508         if(shutdown(s,1))
509                     /* 1 终止 传送操作 */
510             { failed++;close(s);continue;}
511     if(force==0)
512             /*  阻塞等待回应
513              */
514     {
515             /* read all available data from socket */
516         while(1)
517         {
518               if(timerexpired) break;
519           i=read(s,buf,1500);
520                //fprintf(stderr,"%d\n",i);
521               // fprintf(stderr,"%s",buf);
522           if(i<0)
523               {
524                  failed++;
525                  close(s);
526                  goto nexttry;
527               }
528            else
529                if(i==0) break;
530                else
531                    bytes+=i;
532         }
533     }
534     if(close(s)) {failed++;continue;}
535     speed++;
536  }
537 }

socket.c

 1 /* $Id: socket.c 1.1 1995/01/01 07:11:14 cthuang Exp $
 2  *
 3  * This module has been modified by Radim Kolar for OS/2 emx
 4  */
 5
 6 /***********************************************************************
 7   module:       socket.c
 8   program:      popclient
 9   SCCS ID:      @(#)socket.c    1.5  4/1/94
10   programmer:   Virginia Tech Computing Center
11   compiler:     DEC RISC C compiler (Ultrix 4.1)
12   environment:  DEC Ultrix 4.3
13   description:  UNIX sockets code.
14  ***********************************************************************/
15
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <fcntl.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <netdb.h>
22 #include <sys/time.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28
29 int Socket(const char *host, int clientPort)
30 {
31     int sock;
32     unsigned long inaddr;
33     struct sockaddr_in ad;
34     struct hostent *hp;
35
36 //    printf("%s\n",host);
37     memset(&ad, 0, sizeof(ad));
38     ad.sin_family = AF_INET;
39
40     inaddr = inet_addr(host);
41     if (inaddr != INADDR_NONE)
42             /* 无符号长整型和负数比较
43              * 上面这句话有问题, iner_addr 返回一个FFFFFFFF,即-1为错误,在ip地址翻译上
44              * 255.255.255.255,这个也就是 为什么不建议使用 inet_addr的原因*/
45         memcpy(&ad.sin_addr, &inaddr, sizeof(inaddr));
46 else
47     {
48          //   printf("test 4\n");
49         hp = gethostbyname(host);
50         //    printf("test 5\n");
51         if (hp == NULL)
52             return -1;
53         memcpy(&ad.sin_addr, hp->h_addr, hp->h_length);
54     }
55     ad.sin_port = htons(clientPort);
56
57     sock = socket(AF_INET, SOCK_STREAM, 0);
58     if (sock < 0)
59         return sock;
60     if (connect(sock, (struct sockaddr *)&ad, sizeof(ad)) < 0)
61         return -1;
62     return sock;
63 }

**************************************************************************************************

最后放一些写个自己的东西

1. 我学到的字符串更加灵活的应用,尤其是几个以前没有见过的string.h库里的函数

2. 对http协议有了个初步的了解 : http简明解析

3. getopt函数的使用的了解

转载于:https://www.cnblogs.com/dilidingzhi/p/4298096.html

webbench 代码阅读相关推荐

  1. 代码阅读——十个C开源项目

    代码阅读--十个C开源项目 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性 ...

  2. ORB_SLAM2代码阅读(5)——Bundle Adjustment

    ORB_SLAM2代码阅读(5)--Bundle Adjustment 1. 说明 2. Bundle Adjustment(BA)的物理意义 3. BA的数学表达 4. BA的求解方法 4.1 最速 ...

  3. ORB_SLAM2代码阅读(3)——LocalMapping线程

    ORB_SLAM2代码阅读(3)--LocalMapping线程 1.说明 2.简介 3.处理关键帧 4. 地图点剔除 5. 创建新的地图点 6.相邻搜索 6.剔除冗余关键帧 1.说明 本文介绍ORB ...

  4. ORB_SLAM2代码阅读(4)——LoopClosing线程

    ORB_SLAM2代码阅读(4)--LoopClosing线程 1.说明 2.简介 3.检测回环 4.计算Sim3 4.1 为什么在进行回环检测的时候需要计算相似变换矩阵,而不是等距变换? 4.2 累 ...

  5. ORB_SLAM2代码阅读(2)——tracking线程

    ORB_SLAM2代码阅读(2)--Tracking线程 1. 说明 2. 简介 2.1 Tracking 流程 2.2 Tracking 线程的二三四 2.2.1 Tracking 线程的二种模式 ...

  6. ORB_SLAM2代码阅读(1)——系统入口

    ORB_SLAM2代码阅读(1)--系统简介 1.说明 2.简介 3.stereo_kitti.cc 4.SLAM系统文件(System.cc) 4.1 构造函数System() 4.2 TrackS ...

  7. 深度学习项目代码阅读建议

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|机器学习实验室 犹豫很久要不要把读代码这个事情专门挑出来写 ...

  8. JavaScript权威Douglas Crockford:代码阅读和每个人都该学的编程

    作者:Peter Seibel 关于JavaScript Seibel:在程序学习之路上有哪些令你后悔的事情? Crockford:我了解一些语言,但却一直没有机会使用.我花了不少时间学习APL并了解 ...

  9. MFC按钮CXPButton类,代码阅读起来还是挺不错的

    在操手MFC的时候,经常会抱怨MFC界面不如其他的框架或语言,比如VB,C#等等,面对MS在系统上的不断更新换代,我们也越来越追求软件的视觉效果,譬如我们会更喜欢win7下的玻璃效果,看起来很炫. 在 ...

  10. 《代码阅读方法与实践之读书笔记之一》

    <代码阅读方法与实践之读书笔记之一> 阅读代码是程序员的基本技能,同时也是软件开发.维护.演进.审查和重用过程中不可或缺的组成部分.<代码阅读方法与实践之读书笔记之一>这本书围 ...

最新文章

  1. DllMain中不当操作导致死锁问题的分析--导致DllMain中死锁的关键隐藏因子
  2. 【译文】怎样让一天有36个小时
  3. ggClusterNet---一条代码完成全内容微生物网络
  4. 2021-03-01 Matlab 多项式的根求解
  5. inodesusedpercent_Linux运维监控基础采集项
  6. 计算机一级电子表格怎么打开,xls文件怎么打开?其实很简单
  7. Java集合—PriorityQueue底层原理
  8. Stream流中的常用方法_count
  9. Python数据存储:pickle模块的使用讲解(测试代码)
  10. 小知识:vue中的name的作用
  11. Google 也要“勒紧腰带”过日子了!
  12. python产生随机数_python技能:random库的使用
  13. 大一计算机专业选修课,大学计算机类开什么公选课好?
  14. Linux_加密和安全详细介绍
  15. php识别名片,基于php的聚合数据名片识别api调用实例
  16. STM32的RS485通信
  17. 形式语言与自动机 第4章 正规文法和正规集的性质
  18. 如何快速学会三子棋游戏
  19. 网易云亮相GITC,聚合多样化通信与视频云平台
  20. proteus元件大全 仿真元件 电子元器件英文缩写

热门文章

  1. 数学--线性代数--奇异值分解(SVD)
  2. YOLO学习-2:win10(64位)+ python3.6 + TensorFlow-GPU + keras + yolov3测试实践(增加笔记本显卡GPU加速)
  3. java 下拉列表监听_javascript对下拉列表框(select)的操作
  4. 我为什么鼓励工程师写blog
  5. MFC获得主窗口和父窗口指针
  6. JC法在matlab,自贡自流井启闭机--四川闸门厂家产品中心
  7. 数组越界怎么判断_算法连载之求解两个有序数组的中位数
  8. SpringCloud实战与原理---快速入门
  9. rust-let 不可变绑定与可变绑定(4)
  10. go语言基础到提高(13)-同步