[置顶] 嵌入式linux系统基础与编程笔记汇总

时间:2023-01-25 18:35:22

1.  什么是嵌入式系统?

嵌入式系统:

广义上讲:具有特定用途或者功能的计算机软硬件集合体,它以应用为中心,以计算机技术为基础,硬软件可裁剪,适用于应用系统对功耗,成本,体积,可靠性,功能有严格要求的专用计算机系统

狭义上讲:嵌入到对象体中的专用计算机系统

2. 嵌入式系统的特点是什么?

   @最大的特点是嵌入式的cpu工作在为特定用户群设定的系统中,具有低功耗,体积小,集成度高的特点。(把cpu中由板卡完成的任务集成在芯片内部,有利于嵌入式系统趋于小型化,移动能力增强,与网络的耦合度越来越紧密)

   @嵌入式的硬件和软件必须高效地设计,量体裁衣,去除冗余;

   @嵌入式系统中的软件都固化在存储器的芯片或单片机本身中,而不存储在磁盘等载体中,提高了执行速度和可靠性

   @嵌入式系统有较强的生命周期,嵌入式系统与具体应用结合在一起,他的升级换代也与具体产品同步进行

   @嵌入式系统本身不具备自举开发能力,用户不能对程序功能进行修改,必须有一套开发工具和环境。

 面试题:

  嵌入式操作系统和通用操作系统有什么差别?

  多优先级,抢占型,实时操作系统。

  嵌入式操作系统一般没有UI(user interface),体积小,实时性强,对稳定性要求更高。

  嵌入式操作系统强调实时性,并且可裁减。

  要求系统资源的消耗要尽可能的小。


3.  (os)计算机部件:

PC,IR,MAR(A:address),MBR(B;buffer),I/O AR,I/O BR,执行单元

计算机部件可以分为4部分:

[置顶]        嵌入式linux系统基础与编程笔记汇总

@@处理器(CPU):可以对存储器和输入输出设备进行数据交换(MAR:由地址确定特定存储器,MBR:存放写入存储器或从中读出的数据)

处理器中的寄存器(有存储能力,比内存访问速度快,但容量小cache)有两种功能:

1)用户可见寄存器:数据寄存器和地址寄存器;

2)控制和状态寄存器: 程序寄存器(pc,下条指令的地址)和指令寄存器(IR:最近取出指令的内容)

所有处理器含有程序状态字(PWD):包含状态信息;

@@存储器(内存),易失性,(关机后主存储器内容丢失,磁盘存储器内容不丢失),

@@输入输出模块:在外部设备,内存和处理器之间传送数据;缓冲区用于存放临时数据,直到数据被发送出去;

@@系统总线:为3个模块之间提供通信设施

 

4.      (os)高速缓存器(cache)

在cpu与内存之间提供的一个容量小但速度快的存储器,用来解决cpu与内存速度不匹配的问题。

[置顶]        嵌入式linux系统基础与编程笔记汇总

  高速缓存与内存之间数据传输形式:

    当cpu需要从内存读取字节或字(Cpu产生要读取数据的地址RA),首先查看cache中的是否存在,如果有,就直接将其传送给cpu,若是没有,在内存中由固定数目的字节组成一块内存数据传入cache,再由字节或字的形式传送给cpu;

[置顶]        嵌入式linux系统基础与编程笔记汇总[置顶]        嵌入式linux系统基础与编程笔记汇总

 

2011.腾讯校园招聘笔试:

以下关于Cache的叙述中,正确的是(B)

A、CPU中的Cache容量应大于CPU之外的Cache容量

B、Cache的设计思想是在合理成本下提高命中率

C、Cache的设计目标是容量尽可能与主存容量相等

D、在容量确定的情况下,替换算法的时间复杂度是影响Cache命中率的关键因素

有关高速缓存的设计:

 Cache的大小:适当小的可以对性能产生显著地影响,(考虑到成本,cache不会太大)

 块的大小(cache与存储器交换数据的单位):

         @当块由很小变得较大时,由于局部性原理,命中率会先增大

         (局部性原理;位于被访问数据附近的其他数据近期被访问到的几率较大)

        @当块继续变大时,新移进cache的数据用到的可能性小于必须被移出cache的数据再次用到的可能性

映射函数,替换算法:

当数据块读入cache,由映射函数确定其占据哪块cache单元

(1.考虑替换算法LRU(least-recently-used,最近最少使用算法(保证cache中存放的是最近经常使用的数据);

    2.考虑映射函数越灵活,实现确定指定块是否在cache中功能的逻辑 电路越复杂))


cache的读写策略

   为了保证cache与内存之间内容的一致性,防止cpu读写时数据丢失,确保cache中数据不会因为更新而覆盖;必须将cache中的数据及时地更新并且返回到内存中;

     针对cpu对内存的读写访问(cache的读是cpu对内存的读,cache的写是cpu对内存的写);

cache的两种读策略:

1) cache的贯穿读出式:

[置顶]        嵌入式linux系统基础与编程笔记汇总
 流程:
       cpu要对内存读数据,先经过cache,cache在自身中寻找,若是有要求的数据,则将数据返回给cpu,切断cpu对内存的数据   请求,若是不存在,则将数据请求传送给内存;
优点:降低了cpu对主存的访问次数;
缺点:延迟了cpu对主存的访问时间;
2) cache旁路读出式:
[置顶]        嵌入式linux系统基础与编程笔记汇总
流程:
cpu同时向内存和cache发送数据请求,由于cache速度更快,若是命中,则返回数据给cpu,同时切断对内存发送的数据请求;若是没有命中,cache不做任何动作,cpu直接访问内存。
优点:没有时间延迟
缺点:每次cpu都要访问内存,占用了部分总线的时间;


cache的两种写策略:(决定存储器写操作的时间)

    当cache中的内容改变,必须在其被移出cache前写回内存中。

    @当块被更新,发生写操作(通写方式,也叫全写方式)

[置顶]        嵌入式linux系统基础与编程笔记汇总

   原理:cpu每次写数据,在写cache命中时,同时写入cache和内存中;若写cache没有命中,则只写入内存中;

优点:保证l cache 中的数据与内存中的数据高度一致;

缺点:降低写速度并占用了部分总线时间;

    @当块被替换,发生写操作(写回方式,内存中数据更新不及时,会妨碍多处理器操作,和I/O直接内存读取)

    [置顶]        嵌入式linux系统基础与编程笔记汇总

     原理:数据一般只写到cache中,不写入内存中(减少了访问内存的次数,从而提高了效率);

                  这时,cache中的数据更新但是内存中的数据没有同步更新,(解决方法:为每块cache设置一个标志位,用来表明cache  的某块是否被修改过),当某块要被替换出去时,若块没有被修改过,则无需回写到内存,若是被修改过的块,则写回内存


网络系统编程:

1.      基本的网络模型:

                OSI七层模型                ,       TCP/IP四层模型

             [置顶]        嵌入式linux系统基础与编程笔记汇总

物理与数据链路层:包括os的设备驱动程序和计算机对应的网卡,一起处理传输媒介的物理接口细节

网络层:处理分组在网络中的活动,将数据封装,使每块数据包能够到达目的主机(但是不去检查是否被正确接收)

(网络层的协议包括IP协议(网际协议),ICMP(internet互联网控制报文协议),IGMP(internet互联网管理协议))

传输层:为两台主机的应用程序提供端到端的服务。

        (传输协议:TCP(传输控制协议),UDP(用户数据报协议),

具体有关这两个协议内容参考我的博文《TCP与UDP的区别》

应用层:负责处理特定的应用程序细节。

        (如:Telnet远程登录,FTP文件传输协议,

SMTP(简单邮件传输协议),SNMP(简单网络管理协议))

 

2.      数据的封装与解包:

IP地址(点分十进制表示):每台电脑都有至少一个与其他计算机不重复的地址,是在Internet中唯一标识该计算机的一个32位无符号整数。

端口号:用于区别同一台电脑的不同服务程序(每个服务程序有自己的端口号)。

        TCP、UDP用16位存放端口号,每台电脑有2^16-1个端口(0端口号被保留)。Internet 中套接字地址由IP,端口号组成。另外一些端口号由IANA(The Internet Assigned Numbers Authority,因特网号码指派管理局) 固定分配给应用如FTP,HTTP,Telnet等;

 

   数据在通信过程中某一端是向下通过协议栈,而在另一端是向上通过协议栈

[置顶]        嵌入式linux系统基础与编程笔记汇总

  

数据包每到达一个新的层次,进行相应的数据包头部的封装和解包

依次添加:HTTP头部 -> TCP头部 -> IP头部 -> 以太网头部;

另一端依次解包-》以太网头部-》IP头部(检测IP地址是否正确)-》TCP头部(数据包重组)-》HTTP头部(确定端口号,提交给对应的应用程序)

 

腾讯面试题:

1.      HTTP和CGI是什么?

HTTP:

HTTP(HyperText Transport Protocol)是超文本传输协议;

CGI:
  Common Gateway Interface,简称CGI。在物理上是一段程序,运行在服务器上,提供同客户端 HTML页面的接口。这样说大概还不好理解。那么我们看一个实际例子: 现在的个人主页上大部分都有一个留言本。留言本的工作是这样的:先由用户在客户端输入一些信息,如名字之类的东西。接着用户按一下“留言”(到目前为止工作都在客户端),浏览器把 这些信息传送到服务器的CGI目录下特定的cgi程序中,于是cgi程序在服务器上按照预定的方法进行处理。在本例中就是把用户提交的信息存入指定的文件 中。然后cgi程序给客户端发送一个信息,表示请求的任务已经结束。此时用户在浏览器里将看到“留言结束”的字样。整个过程结束。

2, TCP的三次握手, TIME_WAIT和CLOSE_WAIT状态是什么?
  具体答案内容参考我的博文《TCP与UDP的区别》

图1,3中客户与服务器都在同一个局域网,(LAN)当客户端与服务器在不同的局域网中,可以通过路由器(Router)将这两个局域网连接到广域网(WAN) 图1.4

[置顶]        嵌入式linux系统基础与编程笔记汇总

(LAN)localarea network:

一种覆盖一座或几座大楼、一个校园或者一个厂区等地理区域的小范围的计算机网)

(WAN)widearea network:

用来连接不同地区局域网的互联,实现不同局域网之间(不同地区,城市,国家)计算机通信的远程计算机网

(Router)它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号的设备。路由和交换之间的主要区别就是交换发生在OSI参考模型第二层(数据链路层),而路由发生在第三层,即网络层。这一区别决定了路由和交换在移动信息的过程中需使用不同的控制信息,所以两者实现各自功能的方式是不同的。

计算机网络中各层对等实体间交换的单位信息为:协议数据单位(PDU)

应用层对等实体间交换的PDU成为 数据 或者 记录;

传输层对等实体间交换 PDU的分节 或 数据报

网络层对等实体间交换 PDU的分组 或 包

链路层对等实体间交换 PDU的帧

[置顶]        嵌入式linux系统基础与编程笔记汇总


Linux系统编程面试题:                                                              

9. 一台主机要实现通过局域网与另一个局域网通信,需要做的工作是 C 。                                          

A 配置域名服务器
B 定义一条本机指向所在网络的路由
C 定义一条本机指向所在网络网关的路由(见图1,4)
D 定义一条本机指向目标网络网关的路由

14. 在局域网络内的某台主机用ping命令测试网络连接时发现网络内部的主机都可以连同,而不能与公网连通,问题可能是 C。
A 主机IP设置有误
B 没有设置连接局域网的网关
C 局域网的网关或主机的网关设置有误
D 局域网DNS服务器设置有误

3.     字节序:大于一个字节类型的数据在内存中存放顺序

[置顶]        嵌入式linux系统基础与编程笔记汇总

字节序分为大端字节序和小段字节序。

大端字节序:把最重要的位放在字的最前面,字节顺序与地址顺序一致;(即高位字节放在内存的低地址端,低位字节放在内存的高地址端)

小端字节序:把最重要的位放在字的最后面,字节顺序与地址顺序相反。(即低位字节放在内存的低地址端,高位字节放在内存的高地址端)

网络协议使用网络字节序,属于大端字节序。

编程判断字节序的方法:


[置顶]        嵌入式linux系统基础与编程笔记汇总

华为面试题:

请给出如下这段程序的结果,该程序运行在32位x86体系cpu上(程序以斜体字给出)

chara[]={"abcdef"};

charb[]={'a','b','c','d','e','f'};

union

    {

        struct

        {

             unsigned s1:2;

             unsigned s2:3;

             unsigned s3:3;

        }t;

        char d;

    }s;

char*pta = (char *)0x1200;

char*ptb = (char *)0x1218;

int_tmain(int argc, _TCHAR* argv[])

{

    s.d = 100;

    printf("%d %d %d %d%d%d\n",

strcmp(a,b),sizeof(a),strlen(a),sizeof(s),  s.t.s3,   (ptb-pta));

    return 0;

}

答案:0 7 6 4 3 24

分析:

第一个0说明两个字符数组相同。这里主要考点在于要应试者知道strcmp这一常用的ANSI C库函数的输出,如果两个字符串相等,输出应该是0。

第二个7以及第三个6主要是要应试者分清楚编译器对于字符串数组的大小(容量)是包含结束符’0x0’的,而strlen是不包含结束符’0x0’的。

第四个4是要检查应试者对于联合的理解,通常在默认情况下,32位cpu(编译器)默认的对齐方式是字对齐,就是按32位来对齐,

因此看联合s中有一个是位域的unsigned,还有一个是char,取容量(占得多)的一个就是unsigned为该联合的大小(sizeof)。

第五个3主要考位域概念,而且考cpu字节序。位域s经过s.d=100这样的赋值后,在x8632位*下内存(或寄存器)中的二进制

表示为01100100 00000000 00000000 00000000,因此s.t.s3是0b111,s.t.s2是0b001,s.t.s1是0b00,这里应用的是x86小头序。

注意位域定义是不能跨字节的,但是这个题目没有出跨字节的位域。

第六个24是考指针概念,两个指针相减,得指针之间的偏移量。


4.      域名解析函数:将域名(Domain Name)转换成网络字节序的协议地址

DNS:(Domain Name System)域名系统

5.      socket编程:

socket套接字是一种通讯机制,其中包含一整套调用接口和数据结构的定义。给应用程序提供了利用TCP/UDP等网络协议进行通讯的手段

@创建socket套接字

  Socketfd = Int socket(int domain,  inttype,  int protocol )

【】domain:协议族           ->    AF_INET(IPv4)

【】type :协议类型: TCP协议类型:SOCK_STREAM; UDP协议类型:SOCK_DGRAM

【】protocol:指定更精确的协议,一般设置为0,根据前两个参数,自动分配

【】成功返回套接字,否则返回-1

@连接服务器函数

   Intret  = connect(int socketfd, structsockaddr* serv_addr,  int addrlen )

  Connect调用成功,表示连接完成(与第二个参数所指向的套接口地址结构对应的服务器建立连接,函数调用成功后,sockfd赋有服务器的地址),TCP三次握手成功

@关闭套接字:

   【】close(socketfd);

  成功执行表示成功执行TCP关闭连接的4个过程,等待关闭过程完成后,返回0,失败返回-1;

@I/O套接字:

    从已连接的套接字读取数据:

Int ret= read(int socketfd, void* buf, size_t bytes)

   函数正常返回读入的字节数,返回0表示套接字已经关闭,返回-1表示出错

   向已连接的套接字写入数据:

Int ret= write(int socketfd,  void* buf,  size_t bytes)

成功返回写入的字节数,失败返回-1

注意:read和write()函数的4大特性:

NO.1 read()和write()是同步函数,只有完全读写完,程序才能继续往下执行;:

同步函数 VS 异步函数:

同步函数是指,当然执行那个函数时,一定要等它执行完才可以执行下一条函数(或指令),未执行完的话就一直等待下去。

异步函数是指执行那个函数时,不会等待它执行完成就可以执行其他的函数。一般要做大量计算或要占用长时间的函数时要用异步函数,要不然程序就会一直卡在那里不动。

NO.2 都是阻塞形函数,若无数据可供读或者写,程序将在此休眠;

阻塞函数 VS 非阻塞函数:

阻塞函数:调用结果返回之前,当前线程挂起,直到函数得到结果返回;(不同于同步函数,同步函数当前线程还是激活的,只是函数没有返回值而已,但是当前线程还会处理各种其他消息)

非阻塞函数:在函数不能立刻得出结果返回,函数不会阻塞当前线程,而是会立刻返回

NO.3 是不封口函数,不会自动添加结束符‘\0’,当要写入文件可不封口,若是用printf输出,一定在最后封口

NO.4 函数不被硬中断和段中断打断

 

@@bind()函数:绑定端口到套接口

Int ret = bind(int socketfd , structsockaddr* serv_addr, int addrlen )

函数成功返回0,失败返回-1;

@@listen()函数:

     Int ret = listen(int socketfd, intqueuenumber);

函数成功返回0,失败返回-1;

@@accept()函数:

    Int nsock = accept(int socketfd, structsockaddr* ser­_addr, int addrlen )

      函数调用成功返回一个已经与客户端链接的新的描述符nsock;

 

利用上述几个函数,可以完成基于TCP协议的单客户(accept返回一个链接后,就开始处理客户请求,直到客户端关闭,才会调用accept新的链接),半双工的简单网络通讯;

单客户全双工的网络通讯可以通过创建线程实现;

用fork()创建子进程编写并发多进程服务器,实现多个客户同时通讯(程序举例见 我的博文《TCP与UDP的区别》


[置顶]        嵌入式linux系统基础与编程笔记汇总

当accept()函数返回一条连接,int pid=fork()一个进程,pid=0:子进程负责处理read(),write();pid>0:父进程负责不断接待新的客户连接;此时子进程监听套接字close(socketfd);父进程不再需要accept()返回的已连接的套接字,close(nsock);虽然已连接文件描述字被关闭了一个,该套接字的引用计数器减1,但只有计数器减少为(子进程也关闭该套接字),才真正引发TCP关闭的4个过程。

有关I/O复用和异步I/O

@为什么引进I/O复用:

 普通的TCP客户端会同时处理两个输入:标准输入fgets();TCP套接字的read();

 因为fgets(),read()都是阻塞函数;当客户端正阻塞在fgets()上,若服务器端发出FIN信号,客户端并不能立即收到,要等到read()时,发现返回值为0,才知道服务器已经关闭。这可能会耗费大量时间,使得程序的执行效率大大降低;所以,引进I/O复用,相比创建进程和线程,程序的执行效率会更高;

注意:每个读操作read()有两个不同的阶段:

A.    等待数据准备好(对于套接字上的read(),等待数据包到达网络,拷贝至套接字的  缓冲区中)

B.     从内核拷贝数据到进程空间(将数据从内核缓冲区拷贝至应用缓冲区)

@I/O复用模型5大种类:

 阻塞式I/O;非阻塞式I/O;I/O复用(select()和poll());信号驱动I/O(SIGIO);异步I/O

@I/O复用应用典型场合:

  -》程序处理多个文件描述符和套接字时,使用I/O复用;

  -》如果一个TCP服务器要处理同时监听套接字和已连接套接字,一般要使用I/O复用;

  -》如果一个服务器既要处理TCP,又要处理UDP,使用I/O复用;

  -》如果一个服务器要处理多个服务和协议,使用I/O复用;

  -》I/O并不仅仅限制在网络编程,其他类型的应用程序可能也会用到;

I/O复用之 select()(程序举例见 我的博文《TCP与UDP的区别》

 Int nofound=

 select( int maxfd, fd_set *readset, fd_set *writeset, fd_set *execeptset, timeval*timeout )

                     ↓            ↓                                 ↓                                  ↓                ↓

最大描述符+1   读文件描述符集合              异常文件描述符+1   等待超时时间

select()易错点:

NO.1: 别忘记将最大描述符+1;

NO.2: 文件描述符集是值,select()函数返回会将没准备好的bit置为0;所以再次调用     select()时,要用FD_SET()将你感兴趣的文件描述符对应的bit置为1;

NO.3: 如果套接字关闭或者出错,select()会返回该套接字即可读又可写;所以在select(0返回可读状态时,必须查看read()和write()函数的返回值,看是否是套接字关闭;

NO.4:对应监听套接字,select()将返回可读表示该套接字有新的链接或者套接字出错,可用accept()验证,若返回-1表示出错;

而pselect(),相对于select()增加的超时值的精度;

I/O复用之poll():

提供与select()相同的功能,但是在涉及流设备时,提供更多附加信息;

Int  nofound  =

poll(struct pollfd*  fdarray, unsigned long  nfds, int  timeout)

(程序举例见 我的博文《TCP与UDP的区别》

 

6. socket编程之UDP(程序举例见 我的博文《TCP与UDP的区别》

UDP的应用:很多应用层的协议有UDP完成,DNS(域名系统),NFS(网络文件系统),SNMP(简单网络管理协议),多播与广播

创建socket()套接字

@int socketfd=socket(AF_INET,SOCK_DGRAM, 0);

 UDP通讯的I/O:

@int ret =

recvfrom(intsocketfd, void* buff, size_t bytes, int flag,struct sockaddr* from, socklen_t *addrlen);

                                                                                                      ↓(3)

@int ret =

sendto (int sockfd,  const void * buff, size_t nbytes, int flags,  const structsockaddr * to, socklen_t addrlen);

                                                                                                                       ↓(1)                                    ↓(2)

(1):地址结构:含有目的主机地址和端口号;

(2) :(1)地址结构的大小由(2)来决定;

(3): 地址结构:含有发送者的协议地址;

函数正常时将读写字节数作为返回值,返回-1则出错;

其中写操作不会发生阻塞,因为UDP协议不关心对方是否会接收到数据;

同样,recvfrom()接收到返回值为0时,并不与TCP那样表示对方断开连接,UDP的无连接的,所以并不存在UDP的连接断开

 

@服务器端在bind()前,进行套接字设置

-》设置:

Int ret = getsockopt(int socketfd, int level, intoptname, void* optval, socklen_t optlen );

                                                           ↓SOL_SOCKET

-》查看:

Int ret = setsockopt(int socketfd, int level, intoptname, void* optval, socklen_t optlen);

                                                                             ↓(1)

(1):SO_REUSEADDR:允许地址重用,防止端口被其他程序占用而使得bind()失败;

  :SO_BROADCZSE:广播

 

UDP之广播:

广播地址;

IPv4地址表示:{netID,subnetID,hostID}(网络ID,子网ID,主机ID);

用-1表示所有比特为1的字段;

子网广播地址:{netID,subID,-1}

全部子网广播地址:{netID,-1,-1}

网络广播地址:{netID,-1}

受限广播地址:{-1,-1,-1}

 

7.      守护进程(Daemon)

类似DOS的内存驻留程序,能够脱离控制终端,进入后台执行。

8.      系统日志(Syslog)

守护进程没有控制终端,不能将出错信息显示出来,守护进程为了记录事件或者出错日志,一般都用Syslog来输出信息。

系统编程之网络(完)

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

 





                                                                                                                          fmoonstar更新至 2011.11.23