POSIX和SYSTEM的消息队列应该注意的问题

首先看看POSIX的代码:

1.posix_mq_server.c

#include <mqueue.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#define MQ_FILE "/mq_test"
#define BUF_LEN 128

int main()
{
     mqd_t mqd;
    char buf[BUF_LEN];
    int  por = 0;
    int ret = 0;
    struct mq_attr attr;
    attr.mq_flags = 0;
    attr.mq_maxmsg = 3;
    attr.mq_msgsize = 50;
    attr.mq_curmsgs= 0;
    mqd = mq_open(MQ_FILE, O_WRONLY,0666,&attr);
    if (-1 == mqd)
    {
        printf("mq_open error.\n");
        return -1;
    }

    do{
        buf[BUF_LEN-1]='\0';
        printf("MQ_MSG : ");
        scanf("%s", buf);
        if(buf[BUF_LEN-1]!= '\0')
        {
            continue;
        }
        printf("strlen:%d\nMQ_POR : ",strlen(buf));
        scanf("%d", &por);
        ret== mq_send(mqd, buf, strlen(buf)+1, por);
        if (ret != 0)
        {
            perror("mq_send error.\n");
        }
        memset(buf,'\0',BUF_LEN);
    }while(strcmp(buf, "quit"));

    mq_close(mqd);
    mq_unlink(MQ_FILE);

    return 0;
}
2.posix_mq_client.c


#include <mqueue.h>
#include <sys/stat.h>
#include <string.h>
#include <stdio.h>
#define MQ_FILE "/mq_test"
#define BUF_LEN 128

int main()
{
    mqd_t mqd;
    struct mq_attr attr;
    char buf[BUF_LEN + 1] = "quit";
    int cnt;
    int  por = 0;
    attr.mq_flags = 0;
    attr.mq_maxmsg = 128;
    attr.mq_msgsize = 128;
    attr.mq_curmsgs = 0;
    //mqd = mq_open(MQ_FILE, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR, NULL);
    mqd = mq_open(MQ_FILE, O_RDONLY | O_CREAT, 0644, &attr);
    if (-1 == mqd)
    {
        printf("mq_open error.\n");
        return -1;
    }

    do{
        cnt = mq_receive(mqd, buf, BUF_LEN, &por);
        if (0 < cnt)
        {
            printf("mq receive : ");
            fflush(stdout);
            buf[cnt] = '\0';
            printf("%s  por:%d\n", buf,por);
        }

    }while(strcmp(buf, "quit")==0);

    printf("\n");
    mq_close(mqd);
    mq_unlink(MQ_FILE);

    return 0;
}

3.makefile

target:client  server
client: posix_mq_client.c
    gcc posix_mq_client.c -o client -lrt
server:posix_mq_server.c
    gcc posix_mq_server.c -o server -lrt

clean:
    rm -f client server
    rm -f *.o

运行make:

==[]==root@gaoke:~/code$./server
MQ_MSG : fgsdfgsdfgsdfg
MQ_POR : 9
MQ_MSG : dfgsdfgsdfg
MQ_POR : 3
MQ_MSG : dfghsdfhgjghdj
MQ_POR : 6
MQ_MSG : sdfgdgfhgjh
MQ_POR : 2
MQ_MSG : dsfghgjghjkh
MQ_POR : 8
MQ_MSG : sdfgsdfgsdfgsd
MQ_POR : 5
MQ_MSG :

==[]==root@gaoke:~/code$./client
mq receive : fgsdfgsdfgsdfg  por:9
mq receive : dsfghgjghjkh  por:8
mq receive : dfghsdfhgjghdj  por:6
mq receive : sdfgsdfgsdfgsd  por:5
mq receive : dfgsdfgsdfg  por:3
mq receive : sdfgdgfhgjh  por:2
我们发现POSIX是严格按照优先级排序读出的,而且先读出作业优先级最高的作业。

好了再看看我们的SYSTEM是如何进行的,先写个简单的代码调试运行看看结果如何:

首先我先说明一下System V系统的消息对列对象结构:

01
02
03
04
05
06
07
08
09
10
11
12
13
struct msqid_ds {
    struct ipc_perm     msg_perm; // 权限,跟共享内存一样
    struct msg      *msg_first;// 指向队列的第一条消息
    struct msg      *msg_last; // 指向队列的最后一条消息
    msglen_t        msg_cbytes;// 当前队列所占字节数
    msgnum_t        msg_qnum;  // 当前队列的消息数
    msglen_t        msg_qbytes;// 队列允许的最大字节数
    pid_t           msg_lspid; // 最后调用msgsnd的PID
    pid_t           msg_lrpid; // 最后调用msgrcv的PID
    time_t          msg_stime; // 最后调用msgsnd的时间
    time_t          msg_rtime; // 最后调用msgrcv的时间
    time_t          msg_ctime; // 最后调用msgctl的时间
}

使用其中一个IPC机制时,系统内核会维护一个ipc权限对象,用于设置读写权限

1
2
3
4
5
6
7
8
9
struct ipc_perm {
    uid_t   uid;   // owner’s user id
    gid_t   gid;       // owner’s group id
    uid_t   cuid;      // creator’s user id
    gid_t   cgid;      // creator’s group id
    mode_t  mode;  // 读写权限
    ulong_t seq;       // 序列号
    key_t   key;       // IPC key
其次我们还知道在Linux下,消息队列被创建在虚拟文件系统中。(其它实现可能也提供这样的特性,但细节可能不一样)此文件系统可以使用以下命令挂载(由超级用户):
# mkdir /dev/mqueue
# mount -t mqueue none /dev/mqueue

 

1.sys_msq_server.c

#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MQ_FILE "./mq_test"
#define BUF_LEN 128
struct msgbuf {
   long mtype;     /*  message type, must be > 0 */
   char mtext[256];  /*  message data */
};
int  main()
{
    struct msqid_ds info={0};
    struct msgbuf MSG={0};
    key_t key = ftok(MQ_FILE,10);
    int cnt =  msgget(key,IPC_CREAT|0666);//0:取消息队列标识符,若不存在则函数会报错IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错
    if(cnt == -1)
    {
        perror("error!");
    }
    while(1){
        printf("enter the MSG:\n");
        scanf("%s",MSG.mtext);
        MSG.mtype = 1;
        //

        msgsnd(cnt,&MSG,strlen(MSG.mtext)+1,IPC_NOWAIT);// 最后一个参数:0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程
        msgctl(cnt,IPC_STAT,&info);//IPC_STAT:获得msgid的消息队列头数据到buf中IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes

        printf("uid:%d, gid = %d, cuid = %d, cgid= %d\n" , info.msg_perm.uid,  info.msg_perm.gid,  info.msg_perm.cuid,  info.msg_perm.cgid  ) ;
        printf("read-write:%03o, cbytes = %lu, qnum = %lu, qbytes= %lu\n" , info.msg_perm.mode&0777, info.msg_cbytes, info.msg_qnum, info.msg_qbytes ) ;
        system("ipcs -q");
    }
}

 

2.sys_msq_client.c

#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <mqueue.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#define MQ_FILE "./mq_test"
#define BUF_LEN 128
struct msgbuf {
   long mtype;     /*  message type, must be > 0 */
   char mtext[256];  /*  message data */
};
int  main()
{
    struct msqid_ds info={0};
    struct msgbuf MSG={0};
    key_t key = ftok(MQ_FILE,10);
    int cnt =  msgget(key,IPC_CREAT|0666);
    int size =0;
    if(cnt == -1)
    {
        perror("error!");
    }
    while(1){
        size = msgrcv(cnt,&MSG,256,1,IPC_NOWAIT);
        if(size > 0)
        {
               puts(MSG.mtext);
        msgctl(cnt,IPC_STAT,&info);
        printf("uid:%d, gid = %d, cuid = %d, cgid= %d\n" ,info.msg_perm.uid,  info.msg_perm.gid,  info.msg_perm.cuid,  info.msg_perm.cgid  ) ;
        printf("read-write:%03o, cbytes = %lu, qnum = %lu, qbytes= %lu\n" , info.msg_perm.mode&0777, info.msg_cbytes, info.msg_qnum, info.msg_qbytes ) ;
        }
    }
}
3.makefile

target:client  server
client: sys_msq_client.c
    gcc sys_msq_client.c -o client -lrt
server:sys_msq_server.c
    gcc sys_msq_server.c -o server -lrt

clean:
    rm -f client server
    rm -f *.o

然后make运行

==[]==root@gaoke:~/code$./server
enter the MSG:
aaaa
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 5, qnum = 1, qbytes= 65536

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xffffffff 0          root       666        5            1          

enter the MSG:
dddd
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 10, qnum = 2, qbytes= 65536

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xffffffff 0          root       666        10           2          

enter the MSG:
fffff
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 16, qnum = 3, qbytes= 65536

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xffffffff 0          root       666        16           3          

enter the MSG:
ggggg
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 22, qnum = 4, qbytes= 65536

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages   
0xffffffff 0          root       666        22           4          

 ==[]==root@gaoke:~/code$./client
asdfasdfas
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 0, qnum = 0, qbytes= 65536
asdfasdfasdf
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 0, qnum = 0, qbytes= 65536
ssss
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 0, qnum = 0, qbytes= 65536

==[]==root@gaoke:~/code$./client
aaaa
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 17, qnum = 3, qbytes= 65536

dddd
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 12, qnum = 2, qbytes= 65536
fffff
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 6, qnum = 1, qbytes= 65536
ggggg
uid:0, gid = 0, cuid = 0, cgid= 0
read-write:666, cbytes = 0, qnum = 0, qbytes= 65536
由此我们还发现了什么呢?有没有发现SYSTEM的消息输入长度是固定的,然而POSIX的是可变长的。

 

SYSTEM的消息队列函数由msgget、msgctl、msgsnd、msgrcv四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。

1.   msgget函数原型

msgget(得到消息队列标识符或创建一个消息队列对象)

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数说明

得到消息队列标识符或创建一个消息队列对象并返回消息队列标识符

函数原型

int msgget(key_t key, int msgflg)

函数传入值

key

0(IPC_PRIVATE):会建立新的消息队列

大于0的32位整数:视参数msgflg来确定操作。通常要求此值来源于ftok返回的IPC键值

msgflg

0:取消息队列标识符,若不存在则函数会报错

IPC_CREAT:当msgflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列,返回此消息队列的标识符

IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的消息队列,则新建一个消息队列;如果存在这样的消息队列则报错

函数返回值

成功:返回消息队列的标识符

出错:-1,错误原因存于error中

附加说明

上述msgflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定消息队列的存取权限

错误代码

EACCES:指定的消息队列已存在,但调用进程没有权限访问它

EEXIST:key指定的消息队列已存在,而msgflg中同时指定IPC_CREAT和IPC_EXCL标志

ENOENT:key指定的消息队列不存在同时msgflg中没有指定IPC_CREAT标志

ENOMEM:需要建立消息队列,但内存不足

ENOSPC:需要建立消息队列,但已达到系统的限制

如果用msgget创建了一个新的消息队列对象时,则msqid_ds结构成员变量的值设置如下:

Ÿ        msg_qnum、msg_lspid、msg_lrpid、 msg_stime、msg_rtime设置为0。

Ÿ        msg_ctime设置为当前时间。

Ÿ        msg_qbytes设成系统的限制值。

Ÿ        msgflg的读写权限写入msg_perm.mode中。

Ÿ        msg_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。

2.   msgctl函数原型

msgctl (获取和设置消息队列的属性)

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数说明

获取和设置消息队列的属性

函数原型

int msgctl(int msqid, int cmd, struct msqid_ds *buf)

函数传入值

msqid

消息队列标识符

cmd

 

IPC_STAT:获得msgid的消息队列头数据到buf中

IPC_SET:设置消息队列的属性,要设置的属性需先存储在buf中,可设置的属性包括:msg_perm.uid、msg_perm.gid、msg_perm.mode以及msg_qbytes

buf:消息队列管理结构体,请参见消息队列内核结构说明部分

函数返回值

成功:0

出错:-1,错误原因存于error中

错误代码

EACCESS:参数cmd为IPC_STAT,确无权限读取该消息队列

EFAULT:参数buf指向无效的内存地址

EIDRM:标识符为msqid的消息队列已被删除

EINVAL:无效的参数cmd或msqid

EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行

3.   msgsnd函数原型

msgsnd (将消息写入到消息队列)

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数说明

将msgp消息写入到标识符为msqid的消息队列

函数原型

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)

函数传入值

msqid

消息队列标识符

msgp

发送给队列的消息。msgp可以是任何类型的结构体,但第一个字段必须为long类型,即表明此发送消息的类型,msgrcv根据此接收消息。msgp定义的参照格式如下:

    struct s_msg{ /*msgp定义的参照格式*/
     long type; /* 必须大于0,消息类型 */
           char mtext[256]; /*消息正文,可以是其他任何类型*/
    } msgp;

msgsz

要发送消息的大小,不含消息类型占用的4个字节,即mtext的长度

msgflg

0:当消息队列满时,msgsnd将会阻塞,直到消息能写进消息队列

IPC_NOWAIT:当消息队列已满的时候,msgsnd函数不等待立即返回

IPC_NOERROR:若发送的消息大于size字节,则把该消息截断,截断部分将被丢弃,且不通知发送进程。

函数返回值

成功:0

出错:-1,错误原因存于error中

错误代码

EAGAIN:参数msgflg设为IPC_NOWAIT,而消息队列已满

EIDRM:标识符为msqid的消息队列已被删除

EACCESS:无权限写入消息队列

EFAULT:参数msgp指向无效的内存地址

EINTR:队列已满而处于等待情况下被信号中断

EINVAL:无效的参数msqid、msgsz或参数消息类型type小于0

   msgsnd()为阻塞函数,当消息队列容量满或消息个数满会阻塞。消息队列已被删除,则返回EIDRM错误;被信号中断返回E_INTR错误。

 如果设置IPC_NOWAIT消息队列满或个数满时会返回-1,并且置EAGAIN错误。

msgsnd()解除阻塞的条件有以下三个条件:

①    不满足消息队列满或个数满两个条件,即消息队列中有容纳该消息的空间。

②    msqid代表的消息队列被删除。

③    调用msgsnd函数的进程被信号中断。

4.   msgrcv函数原型

msgrcv (从消息队列读取消息)

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

函数说明

从标识符为msqid的消息队列读取消息并存于msgp中,读取后把此消息从消息队列中删除

函数原型

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,

                      int msgflg);

函数传入值

msqid

消息队列标识符

msgp

存放消息的结构体,结构体类型要与msgsnd函数发送的类型相同

msgsz

要接收消息的大小,不含消息类型占用的4个字节

msgtyp

0:接收第一个消息

>0:接收类型等于msgtyp的第一个消息

<0:接收类型等于或者小于msgtyp绝对值的第一个消息

msgflg

0: 阻塞式接收消息,没有该类型的消息msgrcv函数一直阻塞等待

IPC_NOWAIT:如果没有返回条件的消息调用立即返回,此时错误码为ENOMSG

IPC_EXCEPT:与msgtype配合使用返回队列中第一个类型不为msgtype的消息

IPC_NOERROR:如果队列中满足条件的消息内容大于所请求的size字节,则把该消息截断,截断部分将被丢弃

函数返回值

成功:实际读取到的消息数据长度

出错:-1,错误原因存于error中

错误代码

E2BIG:消息数据长度大于msgsz而msgflag没有设置IPC_NOERROR

EIDRM:标识符为msqid的消息队列已被删除

EACCESS:无权限读取该消息队列

EFAULT:参数msgp指向无效的内存地址

ENOMSG:参数msgflg设为IPC_NOWAIT,而消息队列中无消息可读

EINTR:等待读取队列内的消息情况下被信号中断

msgrcv()解除阻塞的条件有以下三个:

①    消息队列中有了满足条件的消息。

②    msqid代表的消息队列被删除。

③    调用msgrcv()的进程被信号中断。

 

消息队列使用程序范例

 

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

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

相关文章

算法(7)-leetcode-explore-learn-数据结构-数组-小结

leetcode-explore-learn-数据结构-数组5-小结1.概述2.例题2.1旋转数组2.2 杨辉三角22.3翻转字符串里的单词2.4反转字符串中的单词32.5 删除排序数组中的重复项2.6 移动零本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官…

fcntl函数详解

功能描述&#xff1a;根据文件描述词来操作文件的特性。 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock); [描述] fcntl()针对(文件)描述符提供控…

使用nohup让程序永远后台运行

使用nohup让程序永远后台运行 Unix/Linux下一般比如想让某个程序在后台运行&#xff0c;很多都是使用 & 在程序结尾来让程序自动运行。比如我们要运行mysql在后台&#xff1a; /usr/local/mysql/bin/mysqld_safe --usermysql &但是加入我们很多程序并不象mysqld一样做…

算法(8)-leetcode-explore-learn-数据结构-链表

leetcode-explore-learn-数据结构-链表11.概述1.1 链表插入操作1.2 链表删除操作2.设计链表本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-list/所…

Mysql索引优化实例讲解

MYSQL描述&#xff1a;一个文章库&#xff0c;里面有两个表&#xff1a;category和article。category里面有10条分类数据。article里面有20万条。article里面有一个"article_category"字段是与category里的"category_id"字段相对应的。article表里面已经把…

给自己的VIM配置

编辑 .vimrc 文件如下&#xff1a; filetype plugin on "autocmd Filetype cpp,c,java,cs set omnifunccppcomplete#Complete set nu set nocp set nobackup let g:C_AuthorName gaoke let g:C_AuthorRef gaoke let g:C_Email gaoketaomee.…

shell一文入门通

简单来说“Shell编程就是对一堆Linux命令的逻辑化处理”。 W3Cschool 上的一篇文章是这样介绍 Shell的 hello world 学习任何一门编程语言第一件事就是输出HelloWord了&#xff01;下面我会从新建文件到shell代码编写来说下Shell 编程如何输出Hello World。 (1)新建一个文件…

算法(9)--两个数的最大公约数

两个数的最大公约数1.辗转相除法求解两个数的最大公约数2.更相减损术求解两个数的最大公约数3.不严格理解1.辗转相除法求解两个数的最大公约数 辗转相除法&#xff1a;两个正整数a和b&#xff08;a>b&#xff09;的最大公约数等于a除以b的余数与b 之间的最大公约数。–如果…

RPC编程

图 3 说明在客户机和服务器之间完成 RPC 涉及的步骤。 图 3. 在客户机和服务器之间完成 RPC 涉及的步骤服务器 RPC 应用程序初始化期间它会向 RPC 运行时库注册接口。需要注册接口是因为&#xff0c;客户机在向服务器发出远程过程调用时&#xff0c;要检查它是否与服务器兼容。…

synchronized使用和原理全解

synchronized是Java中的关键字&#xff0c;是一种同步锁。它修饰的对象有以下几种&#xff1a; 修饰一个方法 被修饰的方法称为同步方法&#xff0c;其作用的范围是整个方法&#xff0c;作用的对象是调用这个方法的对象&#xff1b; 修饰一个静态的方法 其作用的范围是整个…

RPC学习笔记

在查看libc6-dev软件包提供的工具&#xff08;用 dpkg -L libc6-dev 命令&#xff09;的时候&#xff0c;发现此软件包提供了一个有用的工具rpcgen命令。通过rpcgen的man手册看到此工具的作用是把RPC源程序编译成C语言源程序&#xff0c;从而轻松实现远程过程调用。下面的例子程…

算法(10)-leetcode-explore-learn-数据结构-链表双指针技巧

leetcode-explore-learn-数据结构-链表21.概述2.例题2.1 环形链表判断2.2 环形链表22.3 相交链表2.4 删除链表的倒数第N个节点3.小结本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn…

一个简单的游戏服务器框架

最近看到百度空间的一个帖子&#xff0c;不错&#xff0c;在这里整理下&#xff0c;转载至我的博客里&#xff0c;开始自己慢慢琢磨写一个框架。 我先从上层结构说起&#xff0c;一直到实现细节吧&#xff0c;想起什么就写什么。 第一部分 服务器逻辑 服务器这边简单的分为三…

堆和栈的精华大总结

Java内存分配原理 栈、堆、常量池虽同属Java内存分配时操作的区域&#xff0c;但其适用范围和功用却大不相同。 一般Java在内存分配时会涉及到以下区域&#xff1a; ◆寄存器&#xff1a;我们在程序中无法控制 ◆栈&#xff1a;存放基本类型的数据和对象的引用&#xff0c;但…

算法(11)-leetcode-explore-learn-数据结构-链表的经典问题

leetcode-explore-learn-数据结构-链表31.反转一个链表2.移除链表元素3.奇偶链表4.回文链表5.小结本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-l…

探索式软件测试

James A.Whittaker [美] 詹姆斯惠特克&#xff08;软件测试领域绝对的大师&#xff09;著作《Exploratory Software Testing》&#xff0c;中文名《探索式软件测试》&#xff0c;记得当时被这本书深深吸引啦&#xff08;我不知道有多少做测试的小伙伴看过这本书&#xff09;&am…

Linux线程池的设计

我设计这个线程池的初衷是为了与socket对接的。线程池的实现千变万化&#xff0c;我得这个并不一定是最好的&#xff0c;但却是否和我心目中需求模型的。现把部分设计思路和代码贴出&#xff0c;以期抛砖引玉。个人比较喜欢搞开源&#xff0c;所以大家如果觉得有什么需要改善的…

算法(12)-leetcode-explore-learn-数据结构-双链表的设计

leetcode-explore-learn-数据结构-链表4双链表的设计本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn.com/explore/learn/card/linked-list/所有例题的编程语言为python 双链表的设…

安全方面知识

什么是文件上传漏洞 文件上传漏洞是指 由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件 这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。 这种攻击方式是…

CE游戏外挂工具

CHEAT ENGINE(以下简称CE)是我见过的最优秀的游戏作弊工具。它的优点多不胜数&#xff0c;虽然单独从搜索游 戏里面的数值来说&#xff0c;它并不比其他同类软件强多少&#xff0c;但它不仅仅是个游戏修改工具&#xff0c;它还有其他游戏修改软件所没有的一些特点&#xff0c;例…