linux c/c++面试知识点整理(五)

41、linux系统进程间有哪些通信方式

       管道、有名管道、消息队列、信号、共享内存、socket、文件
       管道及有名管道:管道可用于具有亲缘关系进程间的通信,例如父子进程,但是有名管道允许无关系的进程间通信。管道其实就是建立一个FIFO文件,一个进程往里面写数据,另外的进程读取数据。
demo如下:

#include 
#include 
#include 
#include 
#include 

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

int main()
{
    pid_t pid;
    char buf[1024];
    int fd[2];
    char *p = "test for pipe\n";
    if (pipe(fd) == -1)
        sys_err("pipe");

    pid = fork();
    if (pid < 0) 
    {
        sys_err("fork err");
    }
    else if(pid == 0)
    {
        //父进程   
        close(fd[1]);
        int len = read(fd[0], buf, sizeof(buf));
        write(STDOUT_FILENO, buf, len);  //输出到屏幕
        close(fd[0]);
    }
    else
    {
        //子进程
        close(fd[0]);
        write(fd[1], p, strlen(p)); //写入test for pipe
        wait(NULL);
        close(fd[1]);
    }

    return 0;
}

       消息队列:也叫报文队列,消息队列是消息的链接表,包括Posix消息队列和SystemV消息队列,有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的信息,消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
发送消息demo如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct my_msg_st
{
    long int my_msg_type;
    char some_text[BUFSIZ];
};

int main(void)
{
    int running = 1;
    struct my_msg_st some_data;
    int msgid = 0;
    char buffer[BUFSIZ] = {0};
    memset((void*)&some_data, 0, sizeof(some_data));

    /*创建消息队列*/
    msgid=msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid==-1)
    {
        fprintf(stderr,"msgget failed with error:%d\n",errno);
        exit(EXIT_FAILURE);
    }

    /*循环向消息队列中添加消息*/
    while(running)
    {
        memset(buffer, 0, sizeof(buffer));
        printf("Enter some text:");
        fgets(buffer,BUFSIZ,stdin);
        some_data.my_msg_type=1;
        strcpy(some_data.some_text,buffer);

        /*添加消息*/
        if(msgsnd(msgid,(void *)&some_data,BUFSIZ,0)==-1)
        {
            fprintf(stderr,"msgsed failed\n");
            exit(EXIT_FAILURE);
        }

        /*用户输入的为“end”时结束循环*/
        if(strncmp(buffer,"end",3)==0)
        {
            running=0;
        }
    }
    exit(EXIT_SUCCESS);
}

接收消息demo如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct my_msg_st
{
    long int my_msg_type;
    char some_text[BUFSIZ];
};

int main(void)
{
    int running=1;
    int msgid = 0;
    struct my_msg_st some_data;
    long int msg_to_receive=0;
    memset((void*)&some_data, 0, sizeof(some_data));

    /*创建消息队列*/
    msgid=msgget((key_t)1234,0666 | IPC_CREAT);
    if(msgid==-1)
    {
        fprintf(stderr,"msgget failed with error: %d\n",errno);
        exit(EXIT_FAILURE);
    }
    
    /*循环从消息队列中接收消息*/
    while(running)
    {
        /*读取消息*/
        if(msgrcv(msgid,(void *)&some_data,BUFSIZ,msg_to_receive,0)==-1)
        {
            fprintf(stderr,"msgrcv failed with error: %d\n",errno);
            exit(EXIT_FAILURE);
        }

        printf("接收到的消息为: %s",some_data.some_text);

        /*接收到的消息为“end”时结束循环*/
        if(strncmp(some_data.some_text,"end",3) == 0)
        {
            running=0;
        }
    }

    /*从系统内核中移走消息队列*/
    if(msgctl(msgid,IPC_RMID,0) == -1)
    {
        fprintf(stderr,"msgctl(IPC_RMID) failed\n");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

       信号:信号是比较复杂的通信方式,用于通知接收进程有某种事情发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信息语义函数signal外,还支持语义符合Posix 1标准的信号函数sigaction。
       共享内存:共享内存是一种文件映射,使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其他通信机制,如信号量结合使用,来达到进程间的同步及互斥。
demo如下:
写入共享内存:

#include
#include 
#include 
#include
#include

typedef struct _Teacher
{
    char name[64];
    int age;
}Teacher;

int main(int argc, char *argv[])
{
    int ret = 0;
    int    shmid = 0;
    //创建共享内存 ,相当于打开文件,文件不存在则创建
    shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666); 
    if (shmid == -1)
    {
        perror("shmget err");
        return errno;
    }
    printf("shmid:%d \n", shmid);
    Teacher *p = NULL;
    //将共享内存段连接到进程地址空间
    p = (Teacher*)shmat(shmid, NULL, 0);//第二个参数shmaddr为NULL,核心自动选择一个地址
    if (p == (void *)-1 )
    {
        perror("shmget err");
        return errno;
    }
    strcpy(p->name, "aaaa");
    p->age = 33;
    //将共享内存段与当前进程脱离
    shmdt(p);
        
    printf("键入1 删除共享内存,其他不删除\n");
    
    int num = 0;
    scanf("%d", &num);
    if (num == 1)
    {
        //用于控制共享内存
        ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID为删除内存段
        if (ret < 0)
        {
            perror("rmerrr\n");
        }
    }                 

    return 0;    
}

从共享内存读取:

#include
#include 
#include
#include 
#include 
#include
#include

typedef struct _Teacher
{
    char name[64];
    int age;
}Teacher;

int main(int argc, char *argv[])
{
    int ret = 0;
    int    shmid = 0;
    //打开获取共享内存
    shmid = shmget(0x2234, 0, 0); 
    if (shmid == -1)
    {
        perror("shmget err");
        return errno;
    }
    printf("shmid:%d \n", shmid);
    Teacher *p = NULL;
    //将共享内存段连接到进程地址空间
    p = (Teacher*)shmat(shmid, NULL, 0);
    if (p == (void *)-1 )
    {
        perror("shmget err");
        return errno;
    }
    
    printf("name:%s\n", p->name);
    printf("age:%d \n", p->age);
    //将共享内存段与当前进程脱离
    shmdt(p);
    
    printf("键入1 程序暂停,其他退出\n");
    
    while(1)
    {
        sleep(1);
    }       
    return 0;
}

       socket:socket也就是套接字,最普遍的进程间通信机制,可用于不同机器之间的进程间通信。

42、为什么要使用linux作为服务器。

       首先,linux是免费的,而windows需要向微软购买正版授权;
       其次,linux比windows灵活,可以实现很多定制化需求,因为linux可以修改系统内核;
       再次,很多高端服务器组件对linux支持的更好,windows版本的可能功能都不是很完整;
       最后,linux开源,所以很多人为它添砖加瓦,几乎你需要的功能都能找到linux的版本并且都是开源免费的。

43、mysql数据库的引擎

       你能用的数据库引擎取决于mysql在安装的时候是如何被编译的。要添加一个新的引擎,就必须重新编译mysql,在缺省情况下,mysql支持三个引擎:ISAM、MYISAM和HEAP,另外两种类型INNODB和BERKLEY,也常常可以使用。

  • ISAM
           ISAM是一个定义明确且历经时间考验的数据库表格管理方法,它在设计之时就考虑到数据库被查询的次数要远大于更新的次数。因此,ISAM执行读取操作的速度很快,而且不占用大量的内存和存储资源。ISAM的两个主要不足之处在于,它不支持事务处理,也不能够容错,如果你的硬盘崩溃了,那么数据文件就无法恢复了。如果你正在把ISAM用在关键任务应用程序里,那就必须经常备份你所有的实时数据,通过其复制特性,Mysql能够支持这样的备份应用程序。
  • MYISAM
           MYISAM是MySQL的ISAM扩展格式和缺省的数据库引擎,除了提供ISAM里所没有的索引和字段管理的大量功能,MYISAM还使用一种表格锁定的机制,来优化多个并发的读写操作。其代价是你需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的时间。MYISAM还有一些有用的扩展,例如用来修复数据库文件的MYISAMCHK工具和用来恢复浪费空间的MYISAMPACK工具。
           MYISAM强调了快速读取操作,这可能就是为什么MYSQL受到了WEB开发如此青睐的主要原因,在WEB开发中你所进行的大量数据操作都是读取操作。所以,大多数虚拟主机提供商和INTERNET平台提供商只允许使用MYISAM格式。
  • HEAP
           HEAP允许只驻留在内存里的临时表格。驻留在内存使得HEAP比ISAM和MYISAM的速度都快,但是它所管理的数据是不稳定的,而且如果在关机之前没有进行保存,那么所有的数据都会丢失。在数据行被删除的时候,HEAP也不会浪费大量的空间,HEAP表格在你需要使用SELECT表达式来选择和操控数据的时候非常有用。要记住,用完表格后要删除表格。
  • INNODB和BERKLEYDB
           INNODB和BERKLEYDB数据库引擎都是造就MYSQL的灵活性技术的直接产品,这项技术就是mysql++API。在使用mysql的时候,你所面对的每一个挑战几乎都源于ISAM和MYISAM数据库引擎不支持事务处理也不支持外来键。尽管要比ISAM和MYISAM引擎慢很多,但是INNODB和BERKLEYDB包括了对事务处理和外来键的支持,这两点都是前两个引擎所没有的。如前所述,如果你的设计需要这些特性中的一者或者两者,那你就要被迫使用后两个引擎中的一个了。

44、什么是红黑树?

       红黑树,又叫RB树,是一种特殊的二叉查找树,可以自动排序,且红黑树的每个节点都有存储位表示节点的颜色,标识是红或者黑。
       红黑树的特性:
       每个节点或者是黑色,或者是红色;
       跟节点是黑色;
       每个叶子节点是黑色(这里叶子节点是指没有子节点的叶子节点);
       如果一个节点是红色的,则它的子节点必为黑色的;
       从一个节点到该节点子孙节点的所有路径上包含相同数目的黑节点。

45、C程序的内存分配方式

       由上到下(地址从高到低):栈、动态链接库、堆、bbs(未初始化的全局变量)、数据段(存放初始化的全局变量)、文本段(存放代码)

46、select和epoll的区别

       select函数 int select(int n,fd_set* readfds, fd_set* writefds, fd_set* errorfds, struct timeval* timeout);
       第一个参数n代表最大的文件描述符+1
       fd_set是一个集合,存放的是文件描述符
       readfds表示我们要监视这些文件描述符里读变化
       writefds表示我们要监视它所指向的集合里面的文件描述符的写变化
       errorfds表示要监视文件描述符是否发生了错误异常
       timeout若为NULL,则select置于阻塞状态,直到监视的某个文件描述符发生变化才返回
       timeout若等于0秒0毫秒,则select是一个纯粹的非阻塞函数,不管文件描述符是否变化,立即返回。
       timeout大于0时,则在timeout时间内阻塞,timeout时间内若文件描述符有变化则返回,如果超时则立即返回
       返回值:负值 select发生错误
       正值 有文件描述符发生变化
       0 等待超时,没有可读写或者发生错误的文件描述符
       epoll函数与select函数最大的不同在于它不会随着监听fd数目的增长而降低效率,并且select同时监听的fd数目是有限制的,默认最大是1024.
       int epoll_create(int size);//创建epoll句柄,参数size告诉内核这个监听的数目有多大,但最新版本这个参数已经无用了
       int epoll_ctl(); //epoll的事件注册函数,它要先注册需要监听的事件类型
       int epoll_wait();//等待事件的发生
       select是轮询fd,而epoll是先将文件描述符注册到内核,一旦文件描述符发生变化,内核会采用回调机制,激活这个文件描述符,这样epoll_wait便会知道。
       epoll相对于select优点:
       监视的文件描述符不受限制,具体多少根内存有关
       IO的效率不会随着监视fd的数量的增加而降低
       mmap加速内核与用户空间的信息传递,避免了多余的内存拷贝

47、linux下inode的说明

       每个磁盘空间都有一个inode表,inode里面每一个节点存放该空间每个文件的信息,例如:文件的字节数、文件拥有者、所在的组、权限、时间、位置等。
       istat 命令查看单个文件;
       df –i查看磁盘空间inode的使用量。

48、IP、TCP、UDP数据包大小

       MTU,普通局域网最大传输单元,为1500个字节;
       IP数据包首部20个字节,所以IP数据包一般是1480个字节;
       TCP数据包首部20个字节,所以数据包大小为1460个字节;
       UDP数据包首部8个字节,所以数据包大小我1472个字节;
       注意:这里说的首部是固定长度,但后面还有一些可选字段。

49、memcache的特性

       服务器接到客户端请求会先检查memcached,如有则直接返回,不再检查DB
       如memcache没有要找的数据,则检查DB,查到以后返回给客户端,并同时缓冲一份到memcache
       更新DB同时更新memcache,保证数据的一致性
       当分配给memcache内存空间用完之后,会根据LRU(最近最少使用)策略和到期失效策略,先替换失效数据,再替换最近最少使用数据
       memchche在内存中是一个巨大的hast表,它其实就是读数据库改为直接读内存,提高读取速度

50、什么是sql注入

       sql注入:用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据。
       应对办法:可以通过数据库防火墙实现对sql注入攻击的防范,因为sql注入攻击往往是通过应用程序来进攻,可以使用虚拟补丁技术实现,对注入攻击的sql特征识别,实现实时攻击阻断。

你可能感兴趣的:(linux c/c++面试知识点整理(五))