




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 摘 要 linux是一种自由和开放源码的类unix操作系统。目前存在着许多不同的linux,但它们都使用了linux内核。linux可安装在各种计算机硬件设备中,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机、大型机和超级计算机。 linux采用消息队列的方式来实现消息传递。system v的消息队列(message queues)是进程之间互相发送消息的一种异步(asynchronously)方式,在这种情形之下,发送方不必等待接收方检查它的消息即在发送完消息后,发送方就可以从事其它工作了而接收方也不必一直等待消息。 新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从
2、中间来接收。消息队列允许一个或多个进程写消息,一个或多个进程读取消息。linux维护了一系列消息队列的msgque向量表。其中的每一个单元都指向一个msqid_ds的数据结构,完整描述这个消息队列。当创建消息队列的时候,从系统内存中分配一个新的msqid_ds的数据结构并插入到向量表中。关键字: linux , 消息函数 ,分析 目 录摘 要11 课设简介31.1课程设计题目31.2课程设计小组成员32 linux的消息函数主模块功能描述33 linux的消息函数各个子模块功能描述43.1 msgget:43.2 msgsnd:53.3 msgrcv:63.4 msgctl:74 linux的
3、消息函数各个子模块相关函数代码分析结果94.1有关常量、函数及相关错误信息的含义:94.1.1 常量含义:94.1.2 错误信息含义94.1.3 相关函数及文件首部含义94.2函数sys_msgget的分析164.2.1 代码及注释164.3发送消息函数real_msgsnd的分析234.3.1 代码分析234.4接收消息函数real_msgrcv的分析284.4.1 代码及注释284.5函数sys_msgctl的分析334.5.1 代码及注释33心得体会42参考文献431 课设简介1.1课程设计题目linux的消息函数的分析1.2课程设计小组成员 msgget:孙帅,分析消息队列的创建函数(
4、sys_msgget)以及与它相关的函数newque、findkey、msg_init,写出代码分析结果,明确组内成员的明细分工,总体把握组内成员的进度。后期组织组内成员成果汇总进行本组总体报告撰写。王亚璇,画出流程图来表示相关函数之间的相互调用关系。魏蕾,负责查阅资料。 msgsnd:张婷,分析消息的发送函数(real_msgsnd)以及与它相关的函数sys_msgsnd,写出代码分析结果。王鑫坤,画出流程图来表示相关函数之间的相互调用关系。闫瞳,张飞龙,负责查阅资料。 msgrcv:樊德山,分析消息的接收函数(real_msgrcv)以及与它相关的函数sys_msgrcv,写出代码分析结果
5、。赵松,画出流程图来表示相关函数之间的相互调用关系。鹿新宇,孙适,负责查阅资料。 msgctl:刘晶,分析消息队列的控制函数(sys_msgctl)以及与它相关的函数freeque,写出代码分析结果。鞠冰霜,画出流程图来表示相关函数之间的相互调用关系。刘航,负责查阅资料。2 linux的消息函数主模块功能描述linux采用消息队列的方式来实现消息传递。system v的消息队列(message queues)是进程之间互相发送消息的一种异步(asynchronously)方式,在这种情形之下,发送方不必等待接收方检查它的消息即在发送完消息后,发送方就可以从事其它工作了而接收方也不必一直等待消息
6、。新的消息总是放在队列的末尾,接收的时候并不总是从头来接收,可以从中间来接收。消息队列允许一个或多个进程写消息,一个或多个进程读取消息。linux维护了一系列消息队列的msgque向量表。其中的每一个单元都指向一个msqid_ds的数据结构,完整描述这个消息队列。当创建消息队列的时候,从系统内存中分配一个新的msqid_ds的数据结构并插入到向量表中。每一个msqid_ds数据结构都包括一个ipc_perm的数据结构和进入这个队列的消息的指针。另外,linux保留队列的改动时间,例如上次队列写的时间等。msqid_ds队列也包括两个等待队列:一个用于向消息队列写,另一个用于读。 每一次一个进程
7、试图向写队列写消息,它的有效用户和组的标识符就要和队列的 ipc_perm数据结构的模式比较。如果进程可以向这个队列写,则消息会从进程的地址空间写到msg数据结构,放到消息队列的最后。每一个消息都带有进程间约定的,应用程序指定类型的标记。但是,因为linux限制了可以写的消息的数量和长度,可能会没有空间容纳消息。这时,进程会被放到消息队列的写等待队列,然后调用调度程序选择一个新的进程运行。当一个或多个消息从这个消息队列中读出去的时候会被唤醒。从队列中读是一个相似的过程。进程的访问权限一样被检查。一个读进程可以选择是不管消息的类型从队列中读取第一条消息还是选择特殊类型的消息。如果没有符合条件的消
8、息,读进程会被加到消息队列的读等待进程,然后运行调度程序。当一个新的消息写到队列的时候,这个进程会被唤醒,继续运行。3 linux的消息函数各个子模块功能描述3.1 msgget:功能:取得一个消息队列。调用者提供消息队列的键标(用于表示一个消息列的唯一的名字),当这个队列存在的时候,这个系统调用负责返回这个队列的标识号;如果这个队列不存在,就创立一个消息队列,然后返回这个消息队列的标识号。主要由sys_msgget执行。说明:系统调用返回与参数key相关的消息队列的标识符. 若以下事实成立,则与消息队列相关的标识符和数据结构将被创建出来: 若参数key等于ipc_private. 若参数ke
9、y没有存在的消息队列标识符与之相关,同时(msgflg&ipc_creat)为真. 创建消息队列的同时,与新的消息队列标识符相关的数据结构将被初始化为如下: msg_perm.cuid和msg_perm.uid设置为调用进程的有效uid. msg_perm.cgid和msg_perm.gid设置为调用进程的有效gid. msg_perm.mode访问权限比特位设置为msgflg访问权限比特位. msg_qnum,msg_lspid,msg_lrpid,msg_stime,msg_rtime设置为0. msg_ctime设置为当前系统时间. msg_qbytes设置为系统允许的最大值. 返回值:
10、调用成功则返回一个非0值,称为消息队列标识符;否则返回值为-1. 简单框图: 3.2 msgsnd:功能:发送消息到指定的消息队列中。主要由real_msgsnd执行。说明:发送一个消息到由msqid指定消息队列标识号的消息队列. 参数msgp指向一个用户定义的缓冲区,并且缓冲区的第一个域应为长整型,指定消息类型,其他数据放在缓冲区的消息中其他正文区内. 下面是消息元素定义: long mtype; char mtext; mtype是一个整数,用于接收进程选择消息类型. mtext是一个长度为msgsz字节的任何正文,参数msgsz可从0到系统允许的最大值之间变化. msgflg指定操作行为
11、: 若(msgflg&ipc_nowait)是真的,消息并不是被立即发送而调用进程会立即返回. 若(msgflg&ipc_nowait)不是真的,则调用进程会被挂起直到下面情况之一发生: 消息被发送出去. 消息队列标志被系统删除.系统调用返回-1. 调用进程接收到未被忽略的中断信号,调用进程继续执行或被终止. 调用成功后,对应指定的消息队列的相关结构做如下动作: 消息数(msg_qnum)加1. 消息队列最近发送进程号(msg_lspid)改为调用进程号. 消息队列发送时间(msg_stime)改为当前系统时间. 以上信息可用命令ipcs -a看到.返回值:发送成功则返回0,否则返回-1.简单
12、框图:3.3 msgrcv: 功能:用msgrcv函数系统调用从msqid消息队列中读取一条信息并将其放入消息段指针msgp指向的结构。msgsz给出mtext的字节数, 如果所接收的消息比msgsz大且msgflg&msg_noerror为真,则按msgsz的大小截断而不通知调用进程。从消息队列中取得指定类型的消息.。 说明:系统调用从由msqid指定的消息队列中读取一个由msgtyp指定类型的消息到由msgp指向的缓冲区中,同样的,该缓冲区的结构如前所述,包括消息类型和消息正文.msgsz为可接收的消息正文的字节数.若接收到的消息正文的长度大于msgsz,则会被截短到msgsz字节为止(当
13、消息标志msgflg&msg_noerror为真时),截掉的部份将被丢失,而且不通知消息发送进程. msgtyp指定消息类型: 为0则接收消息队列中第一个消息. 大于0则接收消息队列中第一个类型为msgtyp的消息. 小于0则接收消息队列中第一个类型值不小于msgtyp绝对值且类型值又最小的消息. msgflg指定操作行为: 若(msgflg&ipc_nowait)是真的,调用进程会立即返回,若没有接收到消息则返回值为-1,error设置为enomsg. 若(msgflg&ipc_nowait)不是真的,则调用进程会被挂起直到下面情况之一发生: 队列中的消息的类型是有效的. 消息队列标志被系统
14、删除.系统调用返回-1. 调用进程接收到未被忽略的中断信号,调用进程继续执行或被终止. 调用成功后,对应指定的消息队列的相关结构做如下动作: 消息数(msg_qnum)减1. 消息队列最近接收进程号(msg_lrpid)改为调用进程号. 消息队列接收时间(msg_rtime)改为当前系统时间. 以上信息可用命令ipcs -a看到. 返回值:调用成功则返回值等于接收到实际消息正文的字节数.不成功则返回-1.简单框图:3.4 msgctl: 功能:在消息队列上执行指定的操作。根据参数的不同和权限的不同,可以执行检索、删除等等操作。主要由sys_msgctl执行。 说明:系统调用提供一系列消息控制操
15、作,操作动作由cmd定义,以下cmd定义值表明了各操作动作的定义. ipc_stat:将msqid相关的数据结构中各个元素的当前值放入由buf指向的结构中. ipc_set:将msqid相关的数据结构中的下列各元素设置为由buf指向的结构中的对应值. msg_perm.uid msg_perm.gid msg_perm.mode msg_qbytes该命令只能由有效uid等于msg_perm.cuid或msg_perm.uid的进程或有效uid有合适权限的进程操作.只有具有合适权限的用户才能增加msg_qbytes的值. ipc_rmid:删除由msqid指示的消息队列.将它从系统中删除并破坏
16、相关的数据结构. 该命令只能由有效uid等于msg_perm.cuid或msg_perm.uid的进程或有效uid有合适权限的进程操作.返回值:调用成功则返回值为0,否则为-1.简单框图:4 linux的消息函数各个子模块相关函数代码分析结果4.1 有关常量及相关错误信息的含义:4.1.1 常量含义:static struct msqid_ds *msgquemsgmni; /消息队列static int msgbytes = 0; /消息队列中所有消息的总字节数static int msghdrs = 0; /消息队列的队头static unsigned short msg_seq = 0;
17、static int used_queues = 0; /已用的消息队列数static int max_msqid = 0; /消息队列最大的id值 static struct wait_queue *msg_lock = null; /消息队列锁定,不让等待进程进入4.1.2 相关错误信息的含义:einval22/* invalid argument */efault14/* bad address */eidrm43/* identifier removed */eacces13/* permission denied */eagain11/* try again */eintr 4/*
18、interrupted system call */enomem12/* out of memory */e2big 7/* arg list too long */enomsg42/* no message of desired type */enospc28/* no space left on device */enomem12/* out of memory */eperm 1/* operation not permitted */enoent 2/* no such file or directory */eexist17/* file exists */4.1.3 相关函数及文件
19、首部含义: struct msg_receiver struct list_head r_list; /* 等待接收者进程列表*/struct task_struct* r_tsk; /*任务列表*/int r_mode; /* 接收模式*/long r_msgtype; /* 等待的消息模型*/long r_maxsize; /* 最大大小*/struct msg_msg* volatile r_msg; /* 消息结构*/; struct msg_sender struct list_head list; /* 等待发送者进程列表*/ struct task_struct* tsk; /*
20、 任务列表*/; struct msg_msgseg /*每一个消息都要有msg_msg数据结构*/struct msg_msgseg* next;/*消息的下一部分 */;struct msg_msg /: msg消息队列数据结构:/struct list_head m_list; /*用于存放消息的链表*/long m_type; /*消息类型*/ int m_ts; /*消息文本大小*/struct msg_msgseg* next;/*下一个消息*/;struct msg_queue struct kern_ipc_perm q_perm;/*ipc许可证*/time_t q_stim
21、e;/* 最后发送时间*/time_t q_rtime;/* 最后接收时间*/time_t q_ctime;/* 最后修改时间 */unsigned long q_cbytes;/*队列当前的字节数 */unsigned long q_qnum;/*队列中消息的数量 */unsigned long q_qbytes;/*队列的最大字节数*/pid_t q_lspid;/* 最后一个发送者进程的pid*/pid_t q_lrpid;/* 最后一个接受者进程的pid*/struct list_head q_messages; /* 存放消息的队列*/struct list_head q_recei
22、vers; /* 消息接收者的队列*/struct list_head q_senders; /* 消息发送者的队列*/;#define search_any1/*搜索全部*/#define search_equal2/*搜索相等的*/#define search_notequal3/*搜索不相等的*/#define search_lessequal4/*搜索小于等于的*/static atomic_t msg_bytes = atomic_init(0);/*原子变量消息字节数初始值为0*/static atomic_t msg_hdrs = atomic_init(0);/*/static
23、 struct ipc_ids msg_ids;/*消息id*/#define msg_lock(id)(struct msg_queue*)ipc_lock(&msg_ids,id) /* 锁定ipc*/#define msg_unlock(id)ipc_unlock(&msg_ids,id) /* 解锁ipc*/#define msg_rmid(id)(struct msg_queue*)ipc_rmid(&msg_ids,id)#define msg_checkid(msq, msgid)/* 检查ipc*/ipc_checkid(&msg_ids,&msq-q_perm,msgid)#
24、define msg_buildid(id, seq) /* 创建一个消息队列类型的ipc资源标示符*/ipc_buildid(&msg_ids, id, seq)static void freeque (int id);/*释放一个进程队列*/static int newque (key_t key, int msgflg);/*新建一个队列*/#ifdef config_proc_fsstatic int sysvipc_msg_read_proc(char *buffer, char *start, off_t offset, int length, int *eof, void *da
25、ta);/*系统进程消息读取工具*/#endifvoid _init msg_init (void)/*初始化*/ipc_init_ids(&msg_ids,msg_ctlmni);#ifdef config_proc_fscreate_proc_read_entry(sysvipc/msg, 0, 0, sysvipc_msg_read_proc, null);#endifstatic int newque (key_t key, int msgflg)/*新建消息队列*/int id;/*号*/struct msg_queue *msq;/*定义消息队列*/msq = (struct ms
26、g_queue *) kmalloc (sizeof (*msq), gfp_kernel);/*初始化*/if (!msq) return -enomem;id = ipc_addid(&msg_ids, &msq-q_perm, msg_ctlmni);if(id = -1) kfree(msq);return -enospc;msq-q_perm.mode = (msgflg & s_irwxugo);msq-q_perm.key = key;msq-q_stime = msq-q_rtime = 0;msq-q_ctime = current_time;msq-q_cbytes = m
27、sq-q_qnum = 0;msq-q_qbytes = msg_ctlmnb;msq-q_lspid = msq-q_lrpid = 0;init_list_head(&msq-q_messages);init_list_head(&msq-q_receivers);init_list_head(&msq-q_senders);msg_unlock(id);return msg_buildid(id,msq-q_perm.seq);static void free_msg(struct msg_msg* msg)/*释放一个消息*/struct msg_msgseg* seg;seg = m
28、sg-next;kfree(msg);while(seg != null) struct msg_msgseg* tmp = seg-next;kfree(seg);seg = tmp;static struct msg_msg* load_msg(void* src, int len)/*加载消息*/struct msg_msg* msg;struct msg_msgseg* pseg;int err;int alen;alen = len;if(alen datalen_msg)alen = datalen_msg;msg = (struct msg_msg *) kmalloc (siz
29、eof(*msg) + alen, gfp_kernel);if(msg=null)return err_ptr(-enomem);msg-next = null;if (copy_from_user(msg+1, src, alen) err = -efault;goto out_err;len -= alen;src = (char*)src)+alen;pseg = &msg-next;while(len 0) struct msg_msgseg* seg;alen = len;if(alen datalen_seg)alen = datalen_seg;seg = (struct ms
30、g_msgseg *) kmalloc (sizeof(*seg) + alen, gfp_kernel);if(seg=null) err=-enomem;goto out_err;*pseg = seg;seg-next = null;if(copy_from_user (seg+1, src, alen) err = -efault;goto out_err;pseg = &seg-next;len -= alen;src = (char*)src)+alen;return msg;out_err:free_msg(msg);return err_ptr(err);static int
31、store_msg(void* dest, struct msg_msg* msg, int len)/*存储消息*/int alen;struct msg_msgseg *seg;alen = len;if(alen datalen_msg)alen = datalen_msg;if(copy_to_user (dest, msg+1, alen)return -1;len -= alen;dest = (char*)dest)+alen;seg = msg-next;while(len 0) alen = len;if(alen datalen_seg)alen = datalen_seg
32、;if(copy_to_user (dest, seg+1, alen)return -1;len -= alen;dest = (char*)dest)+alen;seg=seg-next;return 0;static inline void ss_add(struct msg_queue* msq, struct msg_sender* mss)/*将一个消息添加到消息队列尾部*/mss-tsk=current;current-state=task_interruptible;list_add_tail(&mss-list,&msq-q_senders);static inline vo
33、id ss_del(struct msg_sender* mss)/*删除一个发送者的消息*/if(mss-list.next != null)list_del(&mss-list);static void ss_wakeup(struct list_head* h, int kill)/*唤醒一个消息*/struct list_head *tmp;tmp = h-next;while (tmp != h) struct msg_sender* mss;mss = list_entry(tmp,struct msg_sender,list);tmp = tmp-next;if(kill)mss
34、-list.next=null;wake_up_process(mss-tsk);static void expunge_all(struct msg_queue* msq, int res) /*去除所有消息*/struct list_head *tmp;tmp = msq-q_receivers.next;while (tmp != &msq-q_receivers) struct msg_receiver* msr;msr = list_entry(tmp,struct msg_receiver,r_list);tmp = tmp-next;msr-r_msg = err_ptr(res
35、);wake_up_process(msr-r_tsk);4.2 函数sys_msgget的分析4.2.1 代码及注释asmlinkage int sys_msgget (key_t key, int msgflg) int id, ret = -eperm;struct msqid_ds *msq;lock_kernel(); /锁内核if (key = ipc_private) /判断调用的参数key中是否指定了ipc_private 即判断调用者需要一个新队列;ret = newque(key, msgflg); /如果调用的参数key中指定了ipc_private则调用newque函数
36、新建一个队列,并返回新建队列的序列号idelse if (id = findkey (key) = -1) /如果调用的参数key中没有指定ipc_private,则调用findkey函数来搜索一下是否有这个键值指定的队列,并用把函数的返回值赋给参数idif (!(msgflg & ipc_creat) /如果key键值未被使用,则判断调用的参数msgflg中是否设置了ipc_creat(00001000)位ret = -enoent; /如果调用的参数msgflg中设置了ipc_creat(00001000)位,则返回错误,错误类型enoent(no such file or directo
37、ry)elseret = newque(key, msgflg); /如果调用的参数msgflg中没有设置ipc_creat(00001000)位,则调用newque函数新建一个队列,并返回新建队列的序列号id else if (msgflg & ipc_creat & msgflg & ipc_excl) /key这个键值已被使用。判断调用的参数msgflg是否标志了ipc_creat(00001000)位和ipc_excl(00002000)位ret = -eexist; /如果调用的参数msgflg中既设置了ipc_creat(00001000)位,又设置了ipc_excl(000020
38、00)位,则返回错误,错误类型eexist(file exists) else /如果有key这个键值指定的队列,则使用这个键值所指明的队列作为当前消息队列msq = msgqueid; /把用findkey返回的这个键值所指明的队列指针赋给当前消息队列if (msq = ipc_unused | msq = ipc_noid) /判断当前消息队列(msgque)项目是否被设置ipc_unused或ipc_noidret = -eidrm; /如果当前消息队列(msgque)项目指向被设置ipc_unused或被设置ipc_noid,则该地方没有消息队列(msgque)或者调用者缺少访问它的权
39、限返回错误,错误类型eacces(identifier removed)else if (ipcperms(&msq-msg_perm, msgflg) /如果当前消息队列指针指既没有向ipc_unused又没有指向ipc_noid,判断是否允许访问进程间通讯资源ipcret = -eacces; /如果返回值非0,则不允许访问进程间通讯资源ipc,返回错误,错误类型eacces(permission denied)elseret = (unsigned int) msq-msg_perm.seq * msgmni + id; /如果返回值id为0,则允许访问进程间通讯资源ipc,序列编号和m
40、sgque下标被编码在返回值里。这个编号将成为调用者要传递给sys_msgsnd、sys_msgrcv,以及sys_msgctl的msgid参数。unlock_kernel();/释放内核return ret; /返回ret值 流程图:定位消息队列函数findkey的分析:static int findkey (key_t key) /定位具有给定键值的消息队列int id;struct msqid_ds *msq;for (id = 0; id msg_perm.key) /判断键值是否匹配return id; /如果匹配的键值被找到,则返回相应的数组下标return -1; /循环结束,但
41、是仍然未找到相互匹配的键值,则返回值1以表示失败流程图:创建消息队列函数newque的分析:static int newque (key_t key, int msgflg) /定位一个没有使用的msgque项,并尝试在那里创建一个新的消息队列int id; /* 定义一个局部变量用于循环搜索消息队列 */struct msqid_ds *msq;struct ipc_perm *ipcp;for (id = 0; id msg_perm;ipcp-mode = (msgflg & s_irwxugo);ipcp-key = key;ipcp-cuid = ipcp-uid = current
42、-euid;ipcp-gid = ipcp-cgid = current-egid;msq-msg_perm.seq = msg_seq;msq-msg_first = msq-msg_last = null;msq-rwait = msq-wwait = null;msq-msg_cbytes = msq-msg_qnum = 0;msq-msg_lspid = msq-msg_lrpid = 0;msq-msg_stime = msq-msg_rtime = 0;msq-msg_qbytes = msgmnb;msq-msg_ctime = current_time;if (id max_
43、msqid) /判断新队列是否建立在消息队列(msgque)中原来最高的已用单元槽之后max_msqid = id; /如果这个新队列被建立在消息队列(msgque)中原来最高的已用单元槽之后,newque就相应地增加max_msqid4.3发送消息函数real_msgsnd的分析 4.3.1代码分析static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) /实现sys_msgsnd的实质内容int id;struct msqid_ds *msq;struct ipc_perm *ipcp
44、; /访问权限控制结构struct msg *msgh;long mtype;if (msgsz msgmax | (long) msgsz 0 | msqid mtype) return efault(bad address); if (mtype msg_perm; /对ipc进行赋值,进程间通讯权限允许 slept:if (msq-msg_perm.seq != (unsigned int) msqid / msgmni) /判断保存在消息队列中的序列号是否和那个msgque参数里的编码相匹配return -eidrm; /如果保存在消息队列中的序列号不和那个msgque参数里的编码相匹
45、配,则返回错误,错误类型eidrm(identifier removed)if (ipcperms(ipcp, s_iwugo) /判断调用者是否拥有写消息队列的权限return -eacces; /如果调用者没有写消息的权限,则返回错误,错误类型eacces(permission denied)if (msgsz + msq-msg_cbytes msq-msg_qbytes) /检查如果提供的消息被写入队列之后是否会超过队列所允许的最大容量 if (msgsz + msq-msg_cbytes msq-msg_qbytes) /检查如果提供的消息被写入队列之后是否会超过队列所允许的最大容量
46、 if (msgflg & ipc_nowait) /队列中没有空间。判断msgflg里的ipc_nowait位是否被设置了return -eagain; /msgflg里的ipc_wait位被设置了,调用者不用等待,返回错误,错误类型eagain(try again)if (signal_pending(current) /调用signal_pending使进程进入休眠状态。首先判断是否有信号正在等待该进程return -eintr; /如果存在正在等待消息,就会用进程的休眠被信号中断的方式来处理它,返回错误,错误类型eintr(interrupted system call)interruptible_sleep_on (&msq-wwait); /如果没有正在等待进程的信号,进程就进入休眠状态,直到有信号到达或一条消息移出队列时才被唤醒go
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度全新托管班学生接送服务合同
- 二零二五年度交通事故交通事故责任划分及医疗费用赔偿协议
- 二零二五年度并购重组财务顾问专项服务合同
- 2025年经济特区普通住宅租赁合同纠纷解决机制合同
- 二零二五年度员工解除劳动合同后竞业禁止及离职手续办理合同
- 二零二五年度企业设备抵押融资合同有效要件解析与实施指南
- 2025年度水利工程款代付与生态修复协议
- 2024年语文知识难点解析试题及答案
- 《安全心理学》(1-14章节)笔记
- DB34-T 626-2023 宣城优.质烤烟规范化移栽技术规程
- 《心理健康情绪释放》主题班会
- 学问海鲜智慧树知到答案2024年中国海洋大学
- 水电站进水口启闭机排架结构及配筋计算书
- 《非遗漂漆团扇》美术教育绘画课件创意教程教案
- 有色金属矿山井巷工程施工及验收规范
- 2024北京电子科技职业学院招聘笔试备考题库及答案解析
- 云南省丽江市南瓜坪水库工程环境影响报告书
- 2024-2029年中国3D裸眼技术行业市场发展分析及发展趋势与投资前景研究报告
- 24春国家开放大学《机电一体化系统综合实训》大作业参考答案
- 设备材料进场报验单
- 英文版中国故事绘本愚公移山
评论
0/150
提交评论