UNIX环境高级编程-第一章

2023-05-16

1.UNIX体系结构:

严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核,因为它相对较小,而且位于环境的核心。图1-1显示了UNIX系统的体系结构。
在这里插入图片描述

内核的接口被称为系统调用(system call)。公用函数库构建在系统调用接口之上,应用程序既可以使用公用函数库,也可以使用系统调用。shell时一个特殊的应用程序,为运行其他应用程序提供了一个接口。
从广义上说,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并使计算机具有自己的特性。这里所说的其他软件包括系统使用程序(system utility),应用程序,shell以及公用函数库等。
例如,Linux时GNU操作系统使用的内核。一些人将这种操作系统称为GNU/Linux操作系统,但是,更常见的是简单称其为Linux。虽然这种表达方式在严格意义上并不正确,但鉴于“操作系统”这个词的双重含义,这种叫法还是可以理解的。

2.登录

(1)登录名:
用户在登录UNIX系统时,先键入登录名,然后键入口令。系统在其口令文件(通常是/etc/passwd文件)中查看登录名。口令文件中的登陆项由7个以冒号分隔的字段组成,依次是:登录名,加密口令,数字用户ID(205),数字组ID(105),注释字段,起始目录(/home/sar)以及shell程序(/bin/ksh)。
例:sar: x:205:105:Stephen Rago:/home/sar:/bin/ksh
目前,所有的系统已将加密口令移到另一个文件中。第6章将说明这种文件以及访问它们的函数。
(2)shell:
用户登陆后,系统通常先显示一些系统信息,然后用户向shell程序键入命令。(当用户登录时,某些系统启动一个视窗管理程序,但最终总会有一个shell程序运行在一个视窗中)。shell是一个命令行解释器,它读取用户输入,然后执行命令。shell的用户输入通常来自于终端,有时则来自于文件(称为shell脚本),图1-2总结了UNIX系统中常见的shell。
在这里插入图片描述

系统从口令文件中相应的用户登陆项最后一个字段中了解到应该为该登录用户执行哪一个shell。
自V7以来,由由Steve Bourne在贝尔实验室开发的Bourne shell得到了广泛应用,几乎每一个现有的UNIX系统都提供Bourne shell,其控制流结构类似于Algol 68。
C shell是由Bill Joy在伯克利开发的,所有BSD版本都提供这种shell。另外,AT&T的System V/386 R3.2和System V R4(SVR4)也提供了C shell(下一章将对这些不同版本的UNIX系统做更多说明)。
C shell是在第6版shell而非Bourne shell的基础上构造的,其控制流类似于C语言,它支持Bourne shell没有的一些特色功能,例如作业控制,历史机制以及命令行编辑等。
Korn shell是在Bourne shell的后继者,它首先在SVR4中提供。
Korn shell是由贝尔实验室的David Korn开发的,在大多数UNIX系统系统上运行,但在SVR4之前,通常它需要另行购买,所以没有其他两种shell流行。它与Bourne shell向上兼容,并具有使C shell广泛得到应用的一些特色功能,包括作业控制以及命令行编辑等。
Bourne-again shell是GNU shell,所有Linux系统都提供这种shell。它的设计遵循POSIX标准,同时也保留了与Bourne shell的兼容性。它支持C shell和Korn shell两者的特殊功能。
TENEX C shell是C shell的加强版本。它从TENEX操作系统借鉴了很多特殊,例如命令完备。
POSIX 1003.2标准对shell进行了标准化。这项规范基于Korn shell和Bourne shell的特性。

3.文件和目录:

(1)文件系统
Unix文件系统是目录和文件的一种层次结构,所有东西的起点是称为根(root)的目录,这个目录的名称是一个字符"/"。
目录是一个包含目录项的文件。在逻辑上,可以认为每个目录项都包含一个文件名,同时还包含说明该文件属性的信息。文件属性是指文件类型,文件大小,文件所有者,文件权限以及文件最后的修改时间等。stat和fstat函数返回包含所有文件属性的一个信息结构。第4章将详细说明文件的各种属性。
目录项的逻辑试图与实际存放在磁盘上的方式是不同的。UNIX文件系统的大多数实现并不在目录项中存放属性,这是因为当一个文件具有多个硬链接时,很难保持多个属性副本之间的同步。这一点将在第4章讨论硬链接时理解得更明晰。
(2)文件名
目录中的各个名字称为文件名。只有斜线/和空字符这两个字符不能出现在文件名中。斜线用来分隔构成路径的各个文件名,空字符则用来终止一个路径名。尽管如此,好的习惯还是只使用常用印刷字符的一个子集作为名字符。
创建新目录时会自动创建了两个文件名:.(称为点),.(称为点点)。点指向当前目录,点点指向父目录。在最高层次的根目录中,点点与点相同。
(3)路径名
由斜线分割的一个或多个文件名组成的序列构成路径名,以斜线开头的路径名称称为绝对路径名,否则称为相对路径名。相对路径名指向相对于当前目录的文件。文件系统根的名字(/)是一个特殊的绝对路径名,它不包含文件名。
(4)工作目录
每个进程都有一个工作目录,有时诚其为当前工作目录。所有相对路径名都从工作目录开始解释。进程可以用chdir函数更改其工作目录。
例如,相对路径名doc/memo/joe指的是当前工作目录中的doc目录中的memo目录中的文件joe。从该路径名可以看出,doc和memo都应当是目录,但是不能分辨joe是文件还是目录。

4.输入输出

(1)文件描述符
文件描述符通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,它都返回一个文件描述符。在读,写文件时,可以使用这个文件秒数符。
(2)标准输入,标准输出和标准错误
按惯例,每当运行一个新程序时,所有的shell都为其打开3个文件描述符,即标准输入,标准输出以及标准错误。如果不做特殊处理,例如就像简单的命令ls,则这3个描述符都链接向终端。大多数shell都提供一种方法,使其中任何一个或所有这3个描述符都能重新定向到某个文件,例如:
ls > file.list
执行ls命令,其标准输出重新定向到名为file.list的文件。
(3)不带缓冲的IO
函数open,read,write,lseek以及close提供了不带缓冲的IO。这些函数都是用文件描述符。
实例:程序1-4

#include "apue.h"
#define BUFFSIZE 4096
int main(void)
{
	int n;
	char buf[BUFFSIZE];
	
	while((n==read(STDIN_FILENO,buf,BUFFSIZE))>0)
		if (write(STDOUT_FILENO,buf,n)!=n)
			err_sys("write error");
	if (n<0)
		err_sys("read error");
	exit(0);
}

①头文件<unistd.h>(包含与apue.h)及两个常量STDIN_FILENO和STDOUT_FILENO是POSIX标准的一部分。头文件<unistd.h>包含了很多UNIX系统服务的函数原型,例如程序1-4中的read和write。
②两个常量STDIN_FILENO和STDOUT_FILENO定义在<unistd.h>头文件中,它们指定了标准输入和标准输出的文件描述符。在POSIX标准中,它们的值分别是0和1。
③3.9将详细讨论BUFFSIZE常量,说明它的各种不同值将如何影响程序的效率。此程序总能复制任一UNIX普通文件。
④read函数返回读取的字节数,此值用作要写的字节数。当到达输入文件的尾端时,read返回0,程序停止执行。如果发生了一个都错误,read返回-1。
⑤如果将该程序编译成标准名称a.out文件,以下列方式执行:

./a.out > data

那么标准输入时终端,标准输出则重新定向至文件data,标准错误也是终端。如果此输出文件并不存在,则shell会创建它。该程序将用户键入的各行复制到标准输出中,键入文件结束符(Ctrl+D)时,将终止本次复制。
若以下列方式执行该程序:

./a.out < infile > outfile

会将名为infile文件的内容复制到名为outfile的文件中。
(4)标准IO
标准IO函数为那些不带缓冲的IO函数提供了一个提供了一个带缓冲的接口。使用标准IO函数无需担心如何选取最佳的缓冲区大小,如代码1-4的BUFFSIZE常量的大小。使用标准IO函数还简化了对输入行的处理。例如,fgets函数读取一个完整的行,而read函数读取指定字节数。
我们最熟悉的标准IO函数是printf。在调用printf的程序中,总是包含<stdio.h>,该头文件包括了所有标准IO函数的原型

实例1-5:

#include "apue.h"

int
main(void)
{
	int c;
	while ((c=getc(stdin))!=EOF)
		if(putc(c,stdout)==EOF)
			err_sys("output error");
	if(ferror(stdin))
		err_sys("input error");
	exit(0);
}

函数getc一次读取一个字符,然后函数putc将此字符写到标准输出。读到输入的最后一个字节时,getc返回常量EOF(该常量定义在<stdio.h>)。标准IO常量stdin和stdout也在头文件<stdio.h>中定义,它们分别表示标准输入和和标准输出。

5.程序和进程

(1)程序
程序是一个存储在磁盘上的某个目录中的可执行文件。内核使用exec函数,将程序读入内存,并执行程序。
(2)进程和进程ID
程序的执行实例被称为进程。本书的每一页几乎会使用这一术语。某些操作系统用任务表示正在被执行的程序。
UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID。进程ID总是一个非负整数。
实例1-6:

#include "apue.h"

int
main(void)
{
	printf("hello world from process ID %d\n",(long)getpid());
	exit(0);
}

如果将该程序编译成a.out,然后执行,则结果输出可能每次都不同
此程序运行时,它调用函数getpid得到其进程ID。我们将会在后面看到,getpid返回一个pid_t数据类型。我们不知道它的大小,仅仅知道的是标准会保证它能保存在一个长整型中。因为我们必须在printf函数中指定需要打印的每一个变量的大小,所以我们必须把它的值强制转换为为它可能会用到的最大的数据类型。虽然大多数进程ID可以用整形表示,但用长整型可以提高可移植性。
(3)进程控制
有3个用于进程控制的主要函数:fork,exec和waitpid。(exec函数有7中变体,但经常把它们统称为exec函数)。
实例1-7:

#include "apue.h"
#include <sys/wait.h>
int
main(void)
{
	char buf[MAXLINE]; //MAXLINE定义与apue.h
	pid_t pid;
	int status;
	pritnf("%%");
	while(fgets(buf,MAXLINE,stdin)!=NULL){
		if(buf[strlen(buf)-1]=='\n')
			buf[strlen(buf)-1]=0;
		if((pid=fork())<0)
			err_sys("fork error");
		else if(pid==0){
			execlp(buf,buf,(char *)0);
			err_ret("couldn't execute: %s\n",buf);
			exit(127);	
		}
		if((pid=waitpid(pid,&status,0))<0)
			err_sys("waitpid error");
		printf("%%");
	}
	exit(0);
}

在这个30行的程序中,有很多功能需要考虑
①用标准IO函数fgets从标准输入一次读取一行。当键入文件结束符作为行的第一个字符时,fgets返回一个null指针,于是循环停止,进程也就终止。
②因为fgets返回的每一行都以换行符终止,后随一个null字节,因此用标准C函数strlen计算此字符串的长度,然后用一个null字节替换换行符。这样做是因为execlp函数要求的参数是以null结束而不是以换行符结束的。
③调用fork创建一个新进程。fork对父进程返回新的子进程的进程ID(一个非负整数),对子进程则返回0。
④在子进程中,调用execlp一致性从标准输入读入的命令。这就用新的程序文件替换了子进程原先执行的程序文件。fork和跟随其后的exec两者的组合就是某些操作系统所称的产生(spawn)一个新进程。
⑤子进程调用execlp执行新程序文件,而父进程希望等待子进程终止,这是通过调用waitpid实现的,其参数指定要等待的进程。waitpid函数返回子进程的终止状态。
(4)线程和线程ID
通常,一个进程只有一个控制线程(thread),也就是某一个时刻执行的一组机器指令。对于某些问题,如果有多个控制线程分别作用于它的不同部分,那么解决起来就容易得多。另外,多个控制线程也可以充分利用多处理器系统的并行能力。
一个进程内的所有线程共享同一地址空间,文件秒数符,栈以及与进程相关的属性。因为它们能访问同一存储区,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。
与进程相同,线程也用ID标识。但是,线程ID只在它所属的进程内起作用。一个进程中的线程ID在另一个进程中没有意义。当在一进城中对某个特定线程进行处理时,我们可以使用该线程ID引用它。

6.出错处理

当UNIX系统函数出错时,通常会返回一个负值,而且整形变量errno通常被设置为具有特定信息的值。例如,open函数如果成功执行则返回一个非负文件描述符,如出错则返回-1。在open出错时,有大约15中不同的errno值(文件不存在,权限问题等)。而有些函数对于出错则使用另一种约定而不是返回值。例如,大多数返回指向对象指针的函数,在出错时会返回一个null指针。
文件<errno.h>中定义了errno以及可以赋予它的各种常量。这些常量都以字符E开头。
POSIX和ISO C将errno定义为一个符号,它扩展成为一个可修改的整形左值。它可以是一个包含出错编号的整数,也可以是一个返回出错编号指针的函数。
对于errno应当注意的两条规则。第一条规则:如果没有出错,其值不会被例程清除。因此,仅当函数的返回值指明出错时,才检验其值。第二条规则是:任何函数都不会将errno值设置为0,而且在<errno.h>中定义的所有常量都不为0。
C标准定义了两个函数,它们用于打印出错信息。

#include<string.h>
char * strerror(int errnum);

strerror函数将errnum(通常就是errno值)映射为一个出错消息字符串,并且返回此字符串的指针。
perror函数基于errno的当前值,在标准错误上产生一条出错消息,然后返回。

#include<stdio.h>
void perror(const char *msg);

它首先输出由msg指向的字符串,然后是一个冒号,一个空格,接着是对应于erro值的出错消息,最后是一个换行符。
实例1-8:

#include "apue.h"
#include <errno.h>

int main(int argc,char *argv[])
{
	fprintf(stderr,"EACESS:%s\n",strerror(EACCESS));
	errno=ENOENT;
	perror(argv[0]);
	exit(0);
}

我们将程序名(argv[0],其值是可执行文件名,也就是本文件名)作为参数传递给perror,这是一个标准的UNIX惯例。
出错恢复:
可将在<errno.h>中定义的各种出错分成两类:致命性和非致命性。对于致命性错误,无法执行恢复动作。最多能做的是在用户屏幕上打印出一条出错消息或者将一条出错消息写入日志文件中,然后退出。对于非致命性的错误,有时可以较妥善地进行处理。
与资源相关的非致命性出错包括:EAGAIN,ENFILE,ENOBUFS,ENOLCK,ENOSPC,EWOULDBLOCK,有时ENOMEM也是非致命性出错。当EBUSY指明共享资源正在使用时,也可将它作为非致命性出错处理。当EINTR中断一个慢速系统调用时,可将它作为非致命性出错处理。

7.用户标识

(1)用户ID
口令文件登陆项中的用户ID(user ID)是一个数值,它向系统标识各个不同的用户。系统管理员在确定一个用户的登录名的同时,确定其用户ID。用户不能更改其用户ID。通常每个用户有一个唯一的用户ID。下面将介绍内核如何使用用户ID来检验该用户是否有执行某些操作的权限。
用户ID为0的用户为跟用户(root)或超级用户(superuser)。在口令文件中,通常有一个登录项,其登录名为root,我们称这种用户的特权为超级用户特权。我们将在第4章中看到,如果一个进程具有超级用户特权,则大多数文件权限检查都不在进行。某些操作系统功能只向超级用户提供。
(2)组ID
口令文件登录项页包括用户的组ID,它是一个数值。组ID也是由系统管理员在指定用户登录名时分配的。一般来说,在口令文件中有多个登录项具有相同的组ID。组被用于将若干集合到项目或部门中去。这种机制允许同组的各个成员之间共享资源。
组文件将组名映射为数值的组ID。组文件通常是/etc/group
使用数值的用户ID和数值的组ID设置权限是历史上形成的。对于磁盘上的每个文件,文件系统都存储该文件所有者的用户ID和组ID。存储这两个值只需4个字节。如果使用完整ASCII登录名和组名,则需要更多的磁盘空间。另外,在检验权限期间,比较字符串较之比较整数型更消耗时间。
但是对于用户而言,使用名字比使用数值更方便,所以口令文件包含了登录名和用户ID之间的映射关系,而组文件则包含了组名和组ID之间的映射关系。
实例1-9:

#include "apue.h"
int
main(void)
{
	printf("uid=%d,gid=%d\n",getuid(),getgid());
	exit(0);
}

该程序调用getuid和getgid两个函数获取用户id和组id。
(3)附属组ID
除了在口令文件中对一个登录名指定一个组ID外,大多数UNIX系统版本还允许一个用户属于另外一些组。这一功能是从4.2BSD开始的,它允许一个用户属于多至16个其他的组。登录时,读文件/etc/group,寻找列有该用户作为其成员的前16个记录项就可以得到该用户的附属组ID。POSIX要求系统至少应支持8个附属组,实际上大多数系统至少支持16个附属组。

8.信号

信号(signal)用于通知进程发生了某种情况。例如,若某一进程执行除法操作,其除数为0,则将名为SIGFPE(浮点异常)的信号发送给该进程。进程有以下3中处理信号的方式。
(1)忽略信号,有些信号表示硬件异常,例如,除以0或访问进程地址空间意外的存储单元等,因为这些异常产生的后果不确定,所以不推荐使用这种处理方式
(2)按系统默认方式处理。对于除数为0,系统默认方式是终止该进程
(3)提供一个函数,信号发生时调用该函数,这被称为捕捉该信号。通过提供自编的函数,我们就能知道什么时候产生了信号,并按期望的方式处理它。
很多情况下会产生信号。终端键盘上有两种产生信号的方法,分别称为中断键,通常是Delete键或(Crtl+C)和退出键(通常是Crtl+),它们被用于中断当前运行的进程。另一种产生信号的方法是调用kill函数。在一个进程种调用此函数就可以向另一个进程发送一个信号。
当然这样做也有些限制:当向一个进程发送信号时,我们必须是那个进程的所有者或者是超级用户。

实例1-10:

#include<apue.h>
#include<sys/wait.h>
static void sig_int(int);
int
main(void)
{
	char buf[MAXLINE];
	pid_t pid;
	int status;
	if (signal(SIGINT,sig_int)==SIG_ERR)
		err_sys("signal error");
	printf("%% ");
	while(fgets(buf,MAXLINE,stdin)!=NULL){
		if(buf[strlen(buf)-1]=='\n')
			buf[strlen(buf)-1]=0;
		if((pid=fork())<0)
			err_sys("fork error");
		else if(pid==0){
			execlp(buf,buf,(char *)0);
			err_ret("couldn't execute:%s",buf);
			exit(127);
		}
		if ((pid=waitpid(pid,&status,0))<0)
			err_sys("waitpid error");
		printf("%%");
	}
	exit(0);
}
void sig_int(int signo)
{
	printf("interrnpt\n%%");
}

9.时间值

历史上,UNIX系统使用过两种不同的时间值。
(1)日历时间
该值是自动协调世界时1970年1月1日00:00:00这个特定时间以来所经历过的秒数累计值。这些时间值可用于记录文件最近一次的修改时间等。
系统基本数据类型time_t用于保存这种时间值。
(2)进程时间。
进程时间也被称为CPU时间,用于度量进程使用的中央处理资源。进程时间以时钟滴答计算。每秒钟曾经取50,60,100这种时钟滴答。
系统基本数据类型clock_t保存这种时间值。
当度量一个进程的执行时间时,UNIX系统为一个进程维护3个进程时间值:时钟时间,用户CPU时间,系统CPU时间。
时钟时间又称为墙上时钟时间,它是进程运行的时间总量,其值与系统种同时运行的进程数有关。
用户CPU时间是执行用户指令所用的时间量。系统CPU时间是为该进程执行内核程序所经历的时间。例如,每当一个进程执行一个系统服务时,如read或write,在内核内执行该服务所花费的时间就计入该进程的系统CPU时间。
要取得任一进程的时钟时间,用户时间,系统时间是很容易的,只要执行命令time(1),其参数是要度量其执行时间的命令
time命令的输出格式与所使用shell有关,其原因是某些shell并不运行/usr/bin/time,而是使用一个内置函数测量命令运行所使用的时间。

10.系统调用和库函数

所有的操作系统都提供多种服务的入口点,由此程序向内核请求服务。各种版本的UNIX实现都提供良好定义,数量有限,直接进入内核的入口点,这些入口点被称为系统调用。
UNIX所使用的技术是为每个系统调用在标准C库中设置一个具有同样名字的函数。用户进程用标准C调用序列来调用这些函数,然后,函数有用系统所要求的技术调用相应的内核服务。例如,函数可将一个或多个C参数送入通用寄存器,然后执行某个产生软中断进入内核的机器指令。从应用角度考虑,可将系统调用视为C函数。
C中的通用库函数,虽然这些函数可能会调用一个或多个内核系统调用,但是它们并不是内核的入口点。例如,printf函数会调用write系统调用用以输出一个字符串,但函数strcpy和atoi并不适用任何内核的系统调用。
从实现者的角度来看,系统调用和库函数之间有根本的区别,但从用户角度来看,其区别并不重要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UNIX环境高级编程-第一章 的相关文章

  • 在Java中,执行SQL查询到数据后,存储在哪里了?

    前言 xff1a 我们项目运行过程中 xff0c 肯定会有查询数据库这步操作 xff0c 无论你是MySQL还是Oracle 那么这种情况就必须搞清楚 xff0c 从数据库里查询得到的数据默认存储到哪了 xff0c 为什么一次查询过多的数据
  • Java小知识:摆脱BeanUtil.copyProperties!! 最优的替代方案 -Bean Converter插件使用方式来了~

    前言 xff1a 开发中为什么不推荐使用BeanUtil copyProperties xff1f 使用BeanUtil copyProperties会有哪些严重后果 xff1f 这些就不在这里眼神了哈 xff0c 大家可以自行查阅一下即可
  • Vue小知识: $ is not defined错误解决

    错误原因 xff1a 该错误是未安装JQuery依赖包导致 解决方案 xff1a 安装依赖包 1 执行安装jquery依赖包命令 cnpm install jquery save 2 webpack配置 xff08 1 xff09 在项目根
  • JVM小知识:linux 命令查看jvm堆内存信息

    1 查看当前java进程的pid pgrep lf java 2 查看java堆的详细信息 jmap heap PID 3 查看java堆中对象的相关信息 xff0c 包含数量以及占用的空间大小 jmap histo PID 4 查看监控
  • IDEA小知识:查看内存使用情况的步骤

    1 展示idea自带的内存指标 xff0c 如图 1 图 2 点击File gt 选择Setting gt 进入APPearance gt 勾选Show memory indicator 图 xff08 1 xff09 图 xff08 2
  • 【无标题】

    CMake Error at xxaipkg CMakeLists txt 50 add message files Unknown CMake command add message files Configuring incomplet
  • npm安装淘宝镜像报错

    npm install g cnpm registry 61 https registry npm taobao org 执行命令报错 无法安装cnpm 解决方案 xff1a 用管理员方式打开命令行 xff0c 就可以安装成功了
  • Leetcode——贪心算法(c++和java实现)

    本来有一段时间没有刷题了 xff0c 但是突然发现了这本书LeetCode 101 A LeetCode Grinding Guide C 43 43 Version xff0c 感觉真不错 xff0c 思路简单清晰 xff0c 没有过多的
  • 树莓派3B+安装c++版本opencv3.4.1,配置开发环境以及注意事项

    树莓派3B 43 安装c 43 43 版本opencv3 4 1 xff0c 配置开发环境以及注意事项 树莓派3B 43 ubuntu mate系统的安装 树莓派 xff0c Raspberry Pi xff0c 是一个只有信用卡大小的微型
  • 由frankmocap得到的.pkl文件转为.bvh或者.fbx

    需求 由Frankmocap所得到的 pkl文件转为blender里的 bvh或者Maya里的 fbx Frankmocap github项目地址 2D转3D转 bvh可以看VideoTo3dPoseAndBvh xff0c bvh转3D相
  • centos 安装docker

    查看系统内核版本 docker需要内核版本在3 8以上 centos7 版本是3 10 安装支持aufs CentOS7 默认不支持aufs文件系统 需要自己安装支持aufs的内核 进入repo目录 cd etc yum repo d 下载
  • echarts框架下大数据量展示的解决方案

    echarts 43 大数据量 这是个无解的问题 xff01 大数据量 xff0c 什么样的数据才算大呢 xff1f 在echart 4 5 0版本中 xff0c 画折线图 xff0c 数据线一共1001000条 xff0c 每条数据500
  • Open vSwitch介绍

    Open vSwitch介绍 1 vSwitch功能2 OvS架构3 OvS报文处理3 1 传统OvS方式3 2 OvS 43 DPDK处理方式 4 OvS补充说明4 1 基本概念4 2 匹配项与规则4 2 1 匹配项4 2 2 动作 本节
  • Python写ROS话题

    Python写ROS话题 导入ROS模块发送话题接收话题第一种方式 xff1a rospy Subscriber第二种方式 xff1a rospy wait for message完整程序 多线程处理同时接受多个话题 导入ROS模块 用py
  • Python写ROS程序常用数据结构std_msgs、geometry_msgs、sensor_msgs

    Python写ROS程序常用数据结构 std msgsFloat64MultiArray geometry msgsVector3TwistWrenchPointQuaternionPosePose2D Stamped sensor msg
  • ROS中gazebo配置教程详解

    ROS中gazebo配置教程详解 机器人模型文件获取原始URDF模型文件采用xacro格式改写文件增加gazebo插件描述增加传动transmission最后将上面三个文件合成一个文件 环境XX world文件配置文件 yaml启动文件la
  • gazebo添加末端六维力传感器

    gazebo添加末端六维力传感器 建立六维力矩传感器模型将传感器拼接到机器人模型配置传感器gazebo参数 常用的机器人只支持位置控制 xff0c 但实际运用中 xff0c 却对末端力控制有迫切的需求 xff0c 其中一种常用的方法是基于位
  • gazebo .world文件中导入dae模型的问题

    gazebo world文件中导入dae模型的问题 gazebo环境提供了很多可以直接导入的模型 xff0c 如果想往环境中导入自己的静态模型 xff0c 需将自己的模型转化为dae格式 xff0c 并编写相应的 world文件 准备好da
  • OpenCV单目视觉定位实现方法

    OpenCV单目视觉定位 xff08 测量 xff09 系统 The System of Vision Location with Signal Camera Abstract This passage mainly describes h
  • CMakeLists.txt 语法介绍与实例演练

    一 Cmake 简介 cmake 是一个跨平台 开源的构建系统 它是一个集软件构建 测试 打包于一身的软件 它使用与平台和编译器独立的配置文件来对软件编译过程进行控制 二 常用命令 1 指定 cmake 的最小版本 span class t

随机推荐