版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、TCP/IP在linux下的具体实现(初稿,未整理)目录TCP/IP在linux下的具体实现(初稿,未整理)1目录11 通用TCP/IP逻辑结构;12 .TCP/IP协议栈在linux下的层次22.2跟实现tcp/ip有关的linux基础知识:22.3 各层之间的关系;53基本数据结构63.1 msghdr结构63.2.sk_buff_head结构63 .3socket类型;93.4.INET Socket: sock103.5以上个结构的跳转及函数指针集合.143.6 struct net_device144实例:收发数据包流程图144.2数据接收过程:以下以图表说明(大致原理类似接受过程)
2、:161 通用TCP/IP逻辑结构;与ISO提出的OSI定义网络层次(7层)不同,tcp/ip就定义了五层.应用层传输层网络层数据链路层物理层应用层BSD SocketInet socket(tcp/udp)IP 层数据链路层物理层各层的主要功能及对应的硬件:物理层:定义传输的电平及硬件接口标准.数据链路层:对应的是网卡芯片内部程序,用于在ip包前加上相应的frame信息.可想想成在网卡芯片里有一个进程在干这件事情.直接跟网卡驱动打交道.网络层:用来路由,数据包分片,负责把一个包发到指定的网络号.;传输层:把收到的包传给具体的进程(根据端口号)等,及数据包传输控制,重发,检测功能;应用层:把有
3、用的数据进行重新组装,定义要传输的端口等等;2 .TCP/IP协议栈在linux下的层次LINUX下tcp/ip协议栈是以4.4 BSD为模板,估计目前大多数操作系统以此为模板,稍加改动,支持BSD Socket 编程模型;在服务器端:1. 调用socket()创建一个socket;2. bind()3. listen()4. accept();5. read/write()在客户端1 socket();2 connect();3 read/write();2.2跟实现tcp/ip有关的linux基础知识:在linux下,所有的设备都当作文件节点来管理,网络设备也不例外,即对一个进程中的soc
4、ket进行读写就相当于对进程中的已打开的文件读写,具体的不同体现在读写函数的不同;一下简单介绍一下看看进程,文件系统及socket之间的关系;进程数据结构:/只关心跟文件有关的那部分struct task_struct ./省略大部分内容/* filesystem information */跟进程有关的文件;struct fs_struct *fs;/* open file information */struct files_struct *files;省略了很多很多结构,跟文件有关就fs_struct *fs 跟files_struct *files两个结构;前者是关于文件信息的,后者关
5、于已打开文件的信息;主要关注一下fisle_struct 结构如下定义:struct files_struct atomic_t count;rwlock_t file_lock;/* Protects all the below members. Nests inside tsk-alloc_lock */int max_fds;int max_fdset;int next_fd;struct file * fd;/* current fd array */fd_set *close_on_exec;fd_set *open_fds;fd_set close_on_exec_init;fd_
6、set open_fds_init;struct file * fd_arrayNR_OPEN_DEFAULT;fd_array数组为改进程打开的文件列表.file 对应的为每个具体的文件,file中有个inode结构体,对应着具体的文件系统类型(如常见的文件系统类型:ext2,ntfs,msdos,qnx4,socket_t),这个创建的socket对应的文件系统类型就属于socket_t类型;各结构之间的应用关系如下图示”该文件读写函数文件 进程结构上面仅是稍微介绍一下tcp/ip实现有关的文件系统.大体上可以这么理解的:一个进程创建了一个socket进行网络传输,相当于打开了一个文件,文
7、件类型是socket_t,在编程人员看来相当于是打开了一个普通文件,而后对该socket进行读写时就相当于对普通文件读写一样可以调用read/write了.至于socket的read/write(不同的文件系统实现都不一样,如fat32 跟ext2,ntfs之间都不一样)函数怎样实现属于操作系统的事情;这正是以下要讨论的;在file结构里有个struct file_oprations;用于指向文件的操作函数指针集合,典型定义如下:不同文件系统对应到的具体函数不一样.如对socket操作时相应的函数集合为(应用层时):static struct file_operation socket_fil
8、e_ops=llseek:sock_lseek;/函数read:sock_read,write:sock_write;open:sock_no_open;/没有这个函数,网卡为特殊设备,通过系统调用socket() 来打开.Realse:sock_release;.以上介绍的是跟实现tcp/ip有关的一些linux基础知识,继续回到层次关系; Linux网络系统基本可分为 硬件层/数据链路层,Ip(tcp,ip,arp等)层,INET Socket层,BSD Socket层 和应用层五部分;其中linux内核中包含了前四部分,应用层和BSD SOCKET层之间的应用程序接口以4.4 BSD为模
9、板.Inet socket层在ip协议层上一层,对ip分组排序,控制网络效率等;Ip层即tcp/ip协议栈的互联网层实现部分,整个协议栈的核心部分;硬件层跟数据链路层对应着网卡及其内部程序,网卡驱动程序界于链路层跟ip层之间.2.3 各层之间的关系;网卡驱动调制解调器驱动硬件设备内核应用程序()讨论的核心是图中的内核层及硬件设备层,主要关注在这些不同的逻辑层次上是通过什么样办法把数据包一层一层往下传递或上传的以及各层之间的接口,对于具体的tcp/ip传输控制信息简略介绍以下;先简单介绍一个各层的关系:应用层中操作的对象是socket的文件描述符,通过文件系统定义的通用接口,使用系统调用从用户空
10、间切换到内核空间,控制socket文件描述府对应的就是对BSD SOCKET的操作,从而进入到bsd socket层的操作,在BSD socket层中,操作的socket结构,每一个这样的结构对应的是一个网络连接,通过网络地址族的不同来区分不同的操作方法,判断是否该进入到INET socket层,这一层数据存放在msghdr结构中,在INET socket层,分成udp跟tcp两种连接.这一层操作的对象是sock类型的数据.数据存放在sk_buff结构中.从INET Socket层到IP层,主要是路由过程,发送时确定发送的下一个机器地址,接受时判断是转发该包还是传给INET socket层,i
11、p层是整个网络协议的核心,基本上整个网络安全都是在这里实现的(在这一层,基于2.4版的内核,提供了五个钩子函数可用于防火墙的实现,基于linux的防火墙软件设计都是在这一层下的五个钩子函数里添加自己的防火墙策略(详细可参考:国防科大出版社编的).从ip层到硬件层,即调用网卡驱动程序.下面介绍一下整个协议栈核心的数据结构3基本数据结构整个网络实现中,数据包(在有效数据前加上包头及一些控制信息)是最重要的部分,影响网络速率和效率的关键就在于在内存中对数据包的管理.在内核中,分不同的层次,使用两种数据结构来保存数据.在BSD Socket层内用msghdr结构保存数据,在INET Socket层以下
12、用sk_buff保存数据.前者是为了跟BSD 4.4兼容而定义的.sk_buff是INET Socket及以下层次中存放数据的结构,在不同层次进行数据包传递,就是通过它进行的(有效数据是通过指针指向的,在不同层次间传递包仅需添加改层次上的相应信息到skb_buff里)3.1 msghdr结构struct msghdr /在bsd socket层使用此数据结构void*msg_name;/* Socket name*/intmsg_namelen;/* Length of name*/struct iovec *msg_iov;/* Data blocks*/从应用层传下来的数据,通过指针指向,
13、不是把数据拷贝过来,_kernel_size_tmsg_iovlen;/* Number of blocks*/从应用层传下的数据包个数void *msg_control;/* Per protocol magic (eg BSD file descriptor passing) */_kernel_size_tmsg_controllen;/* Length of cmsg list */unsignedmsg_flags;3.2.sk_buff_head结构此数据结构很重要,在整个tcp/ip实现中,都围绕着它.删除了一些不重要的元素struct sk_buff /* These two
14、members must be first. */struct sk_buff* next;/* Next buffer in list */struct sk_buff* prev;/* Previous buffer in list */struct sk_buff_head * list;/* List we are on*/struct sock*sk;/* Socket we are owned by 跟一个读写此包的sock关联*/struct timevalstamp;/* Time we arrived*/struct net_device*dev;/* Device we a
15、rrived on/are leaving by该包即将要通过网卡设备或已通过的网卡设备*/* Transport layer header */unionstruct tcphdr*th;struct udphdr*uh;struct icmphdr*icmph;struct igmphdr*igmph;struct iphdr*ipiph;struct spxhdr*spxh;unsigned char*raw; h;/tcp/udp层的协议头,在INET Socket层时会填充;/* Network layer header */unionstruct iphdr*iph;struct
16、ipv6hdr*ipv6h;struct arphdr*arph;struct ipxhdr*ipxh;unsigned char*raw; nh/ip层协议头,在ip层时填充; /* Link layer header */union struct ethhdr*ethernet; unsigned char *raw; mac/链路层协议头,在链路层填充;struct dst_entry *dst;/路由信息表,下一个要到达机器地址,此结构里有个output函数,在发包时调用此output把包传给硬件层.整个网络路由表初始化过程不讨论了,/* * This is the control b
17、uffer. It is free to use for every * layer. Please put your private variables there. If you * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ charcb48; /存放控制命令与控制数据,每层都可自由使用.unsigned int len;/* Length of actual data实际数据长度,即tia
18、l-data*/ unsigned int data_len;unsigned intcsum;/* Checksum */unsigned char _unused,/* Dead field, may be reused*/cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type,/* Packet class*/ ip_summed;/* Driver fed us an IP checksum*/_u32priority;/* Packet queueing priority*/atomic_tusers;
19、/* User count - see datagram.c,tcp.c */unsigned shortprotocol;/* Packet protocol from driver. 以太网协议*/常见的有x.25,arp,以太网ipunsigned shortsecurity;/* Security level of packet包优先级*/unsigned inttruesize;/* Buffer size 缓冲区长度,不是)*/unsigned char*head;/* Head of buffer */unsigned char*data;/* Data head pointer
20、*/unsigned char*tail;/* Tail pointer*/unsigned char *end;/* End pointer*/指向实际有效数据(从应用层传下来的数据)的指针void (*destructor)(struct sk_buff *);/* Destruct function*/#ifdef CONFIG_NETFILTER/* Can be used for communication between hooks. */ unsigned longnfmark;/* Cache info */_u32nfcache;/* Associated connectio
21、n, if any */struct nf_ct_info *nfct;#ifdef CONFIG_NETFILTER_DEBUG unsigned int nf_debug;#endif#endif /*CONFIG_NETFILTER*/#if defined(CONFIG_HIPPI)union_u32ifield; private;#endif#ifdef CONFIG_NET_SCHED _u32 tc_index; /* traffic control index */#endif;从这个结构可以看出,skb_buff主要工作在INET Socket层,ip层和硬件层.内核中有很多
22、对此结构操作的函数,由于篇幅有限,不作进一步讨论.3 .3 socket类型;struct socketsocket_statestate;/连接状态,如SS_CONNECTTED和SS_UNCONNECTED两种,unsigned longflags;struct proto_ops*ops;/指向不同地址族的操作函数集合,对INET 地址族值为inet_proto_ops.为一系列函数指针集合.如下示/*static struct file_operation socket_file_ops=/在应用层时,即文件系统socket_I对应的方法llseek:sock_lseek;/函数rea
23、d:sock_read,write:sock_write;open:sock_no_open;/没有这个函数,网卡为特殊设备,通过系统调用socket() 来打开.Realse:sock_release;以后在此socket上read/write系统调用都会转到sock_read/sock_write函数上;*/ 在BSD SOCKET层时,以连接方式SOCK_STREAM为例此时ops初始化为inet_dgram_ops,此结构下的具体函数指针集合如下:/*PF_INET;Inet_release(),inet_bind,inet_stram_connect(),sock_no_sockpa
24、ir(),inet_accept(),inet_getname(),Tcp_poll(),inet_ioctl(),inet_listen(),inet_shutdown(),inet_setsockopt,inet_sendmsg(),inet_recvmsg();*/linux支持的地址族类型:UNIX:用于本机进程间通讯的,类似与共享内存及消息队列INET:INET套接字,建立在TCP/IP实现上的.是这次要讨论的AX.25:/以下几种属于别的网络通讯协议Nowell IPX:AppkeTalk:DDP:struct inode*inode;/文件节点,inode.socket_I成员指
25、向对应的socket结构指针struct fasync_struct*fasync_list;/* Asynchronous wake up list*/struct file*file;/* File back pointer for gc*/struct sock*sk;/很重要的一个数据结构,在INET Socket层中用到,二者互相指向.wait_queue_head_twait;shorttype;unsigned charpasscred;代表BSD Socket层中的socket控制结构.注意在应用层socket()是个函数,用于创建一个socket结构.3.4.INET Soc
26、ket: sock在INET Socket数据结构中,管理数据包存放和调度的数据结构示sock,在INET Socket层以下都使用sock定义如下:/删除了一些次要的元素struct sock /* Socket demultiplex comparisons on incoming packets. */_u32daddr;/* Foreign IPv4 addr*/_u32rcv_saddr;/* Bound local IPv4 addr*/_u16dport;/* Destination port*/unsigned shortnum;/* Local port*/intbound_
27、dev_if;/* Bound device index if != 0*/* Main hash linkage for various protocol lookup tables. */struct sock*next;struct sock*pprev;struct sock*bind_next;struct sock*bind_pprev;volatile unsigned charstate,/* Connection state*/zapped;/* In ax25 & ipx means not linked*/_u16sport;/* Source port*/unsigne
28、d shortfamily;/* Address family*/unsigned charreuse;/* SO_REUSEADDR setting*/unsigned charshutdown;atomic_trefcnt;/* Reference count*/socket_lock_tlock;/* Synchronizer.*/intrcvbuf;/* Size of receive buffer in bytes最大接受缓冲区大小*/wait_queue_head_t*sleep;/* Sock wait queue*/struct dst_entry*dst_cache;/* D
29、estination cache*/rwlock_tdst_lock;atomic_trmem_alloc;/* Receive queue bytes committed已用的收缓冲区*/struct sk_buff_headreceive_queue;/* Incoming packets收到的包放在此队里*/atomic_twmem_alloc;/* Transmit queue bytes committed已用的写缓冲区*/struct sk_buff_headwrite_queue;/* Packet sending queue*/atomic_tomem_alloc;/* o i
30、s option or other */intwmem_queued;/* Persistent queue size */intforward_alloc;/* Space allocated forward. */_u32saddr;/* Sending source*/unsigned intallocation;/* Allocation mode*/intsndbuf;/* Size of send buffer in bytes最大发送缓冲区大小*/*/struct sock*prev;/* Not all are volatile, but some are, so we mig
31、ht as well say they all are. * XXX Make this a flag word -DaveM */volatile chardead,done,urginline,keepopen,linger,destroy,no_check,broadcast,bsdism;unsigned chardebug;unsigned charrcvtstamp;unsigned charuse_write_queue;unsigned charuserlocks;/* Hole of 3 bytes. Try to pack. */introute_caps;intproc;
32、unsigned long lingertime;inthashent;struct sock*pair;/* The backlog queue is special, it is always used with * the per-socket spinlock held and requires low latency * access. Therefore we special case its implementation. */struct struct sk_buff *head;struct sk_buff *tail; backlog;/在此sock在读写时,如有数据到达,
33、新的数据包保存在此结构中,读包时如果receive_queue;没有数据,在看此结构中有无.rwlock_tcallback_lock;/* Error queue, rarely used. */struct sk_buff_headerror_queue;struct proto*prot;#if defined(CONFIG_IPV6) | defined (CONFIG_IPV6_MODULE)union struct ipv6_pinfoaf_inet6; net_pinfo;#endifunion struct tcp_optaf_tcp;#if defined(CONFIG_IN
34、ET) | defined (CONFIG_INET_MODULE)struct raw_opttp_raw4;#endif#if defined(CONFIG_IPV6) | defined (CONFIG_IPV6_MODULE)struct raw6_opttp_raw;#endif /* CONFIG_IPV6 */#if defined(CONFIG_SPX) | defined (CONFIG_SPX_MODULE)struct spx_optaf_spx;#endif /* CONFIG_SPX */ tp_pinfo;interr, err_soft;/* Soft holds
35、 errors that dont cause failure but are the cause of a persistent failure not just timed out */unsigned shortack_backlog;unsigned shortmax_ack_backlog;_u32priority;unsigned shorttype;unsigned charlocalroute;/* Route locally only */unsigned charprotocol;struct ucredpeercred;intrcvlowat;longrcvtimeo;l
36、ongsndtimeo;#ifdef CONFIG_FILTER/* Socket Filtering Instructions */struct sk_filter *filter;#endif /* CONFIG_FILTER */* This is where all the private (optional) areas that dont * overlap will eventually live. */union 除了tcp/ip/udp之外的一些协议的私有数据, protinfo; /* This part is used for the timeout functions.
37、 */struct timer_listtimer;/* This is the sock cleanup timer. */struct timevalstamp;/时间信息./* Identd and reporting IO signals */struct socket*socket;/* RPC and TUX layer private data */void*user_data; /* Callbacks */void(*state_change)(struct sock *sk);void(*data_ready)(struct sock *sk,int bytes);void
38、(*write_space)(struct sock *sk);void(*error_report)(struct sock *sk); int(*backlog_rcv) (struct sock *sk,struct sk_buff *skb); void(*create_child)(struct sock *sk, struct sock *newsk);void (*destruct)(struct sock *sk);3.5以上个结构的跳转及函数指针集合.BSD Socket:proto_opsINET Socket:proto,通过BSD Socket的proto_ops结构将
39、操作对象从socket切换到sock;INET Socket的proto函数指针集合成员如下(以tcp为例,udp也类似)TCP,tcp_close,tcp_v4_connect,tcp_disconnect,tcp_accept,tcp_ioctl,tcp_v4_init_sockTcp_sendmsg,tcp_recvmsg,tcp_v4_do_rcv,./相当于对tcp协议的实现就是对这些函数的实现,考虑到这四个结构的重要性及相互引用的复杂性,归纳一下这四个结构之间的关系及应用的层次:msghdr及socket结构在bsd socket层用到,往下转到inet socket及以下层时就改
40、用sock跟skb_buff结构.在socket中有一个指向sock及inode的指针,但是没有指向msghdr的指针,msghdr中没有任何指向剩下三个的指针.在bsd socket层会把buf数据的指针付给msghd-iov;注意仅仅是指针赋值,不涉及数据拷贝.让iov与buf指向同一数据区.3.6 struct net_device/省略大部分内容void *priv;初始化时指向pci-dev;用于读取一些端口资源。Unsigned char dev_addrlen /mac地址。Int MTU;/相应的函数操作。4实例:收发数据包流程图不分析建立socket()过程了,假设已调用成功
41、了socket(),connect()(服务器端:socket,bind,listen,accept)函数,相应的socket结构已与进程联系在一块了发送数据Send或sendmsg()都类似Write(fd,*buff,len),系统调用,应用层有个防火墙钩子函数,针对dev做一些检查,判断是否发这个包.Ip_finish_output2 skb_buff *skb)如果没有定义NAT功能(网络地址转换,可直接修改源目的地址),直接到ip_finish_ouput().Ip_finish_output(skb_buff *skb )Ip_output(skb_buff *skb)Ip_que
42、ue_xmit2(struct sk_buff *skb)Tp-af_specific-queue_xmit()(tcp头部)此处有个防火墙钩子函数.负责路由过程,加上ip头,打包后给下一层函数.结束skb中以包含tcp,ip头及数据指针.Ip_queue_xmit(struct sk_buff *skb)Socket结构在这个函数中结束,往下改用它指向的sock结构Sock_write(file*file,*buf,len,)Sys_write(int fd,char *buf,size len) /fd 为socket描述府,buf为要发送的数据区.以下内核空间(操作系统接管)用户空间BS
43、D SOCKET层根据得到fd得到文件fileFile-file_operation的write()调用socket结构中对应的proto_ops集合的sendmsg(),对于inet此处为inet_sendmsg此函数中将会首先出现socket与msghdr结构.socket是通过inode-socket_来引用的,把buf的指针付给msghdr中的iov;Sock_sendmsg(socket *sock,msghdr &msg,size)Sock-prot-sendmsg()Inet_sendmsg(socket *sock,msghdr,size)将msghdr结构中的数据转换到sk_
44、buff中,至此,msghdr结束寿命,改用sk_buff存数据,一直到硬件层,此结构极复杂.Tcp_sendmsg(sock *sk,msghdr *msg,size)将待发的数据排到sock-write_queue队列中.Tcp_send_skb(sock *sk,sk_buff *skb,)生成tcp头存在skb数据区中,生成校验码,往下转ip层Tcp_transmit_skb(sock *sk,sk_buf *skb)INET Socket层通过sk-tcp_opt *tp-af_specific-queue_xmit转到Ip层初始化为Ip_queue_xmit判断空间是否够,如果数据
45、长度大于MTU,调用分包函数ip_fragment();不作考虑.,出现并得到netdevice结构,根据路由初始化下一个要到达机器的地址.待续.Neigh_resolve_output(skb_buf *skb)rtl8139_start_xmit()会此函数涉及到Qos管理,从skb中获取网卡dev指针,调用与此网卡对应的驱动程序,若网卡为8139网卡,对应的发送驱动程序函数为rtl8139_start_xmit(),此函数属于硬件驱动层;Dev_queue_xmit(skb)Skb-dst-neighbour-output函数设为neigh_resole_output(),在ip_fin
46、ish_output2()中调用传下来,此来ip层的最后一站,这里会填充硬件mac地址.调用neigh-ops-queue_xmit()进入硬件层,将mac地址拷贝到数据包中Ip层硬件驱动层/链路层至此,整个数据包的发送过程完毕.最后,skb中数据长度应该是tcp包头+ip包头+mac地址长度;4.2数据接收过程:以下以图表说明(大致原理类似接受过程):1 应用层应用层调用函数recv()或recvform()可以接收数据,或可直接针对socket 的文件描述符调用read()直接接收数据,与发送数据类似;2 BSD Socket层类似发送调用sys_read();在bsd socket层类似
47、于发送过程;先看自上向下的过程(即开始在应用层有个read()系统调用,开始读数据,如果没有,在往下几步就睡眠等待)应用层Bsd socket层Recv/recvmsgTcp_v4_do_establishend()Tcp_v4_do_rcv()有数据从网络协议栈中接受数据,自上而下触发的动作到这个函数为止,出现了第一次等待的过程,此函数可能会被动地等待在sk的接收数据队列上,先判断sk-receive_queue中里有没有符合条件的数据,如果有则调用memcpy_toiovec()Inet socket层Read(fd,buf,size)Sock_read()Sys_read()Sock_recvmsg()Inet_recvmsg(socket *sock,msghdr *msg,int size,)tcp_recvmsg(socket *sock,msghdr *msg,int size,)Socket-sock-prot-msg以下改用sock结构Tcp_v4_rcv()接下图从backlog中填充receive_queue队列从skb 中copy有效到msg-iovc中,除掉各种包头,包含tcp,ip,mac,返回,整个收
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 临床头颅MR断层影像解剖(横、冠、彩图)
- 骨密度检测骨质疏松筛查指南
- 私域流量维护策略
- 危险化学品泄漏事故应急演练方案
- 糖尿病低糖饮食配餐方案
- 粉尘防爆职业健康管理指引
- 腰椎间盘突出专项理疗方案
- 玉米大垄密植高产栽培方案
- 脆蜜草莓温室种植技术规范
- 三级安全教育培训实施细则
- 衡阳县岣嵝峰林场招聘社区网格员考试试题附答案详解
- 2026云南昆明市国和勘察规划设计院有限公司招聘工作人员3人考试备考试题及答案解析
- 低碳城市智慧路灯节能改造升级方案
- 第二轮土地承包到期后再延长30年试点工作意见政策解读
- 2026年监考人员培训试题及答案
- 2026年上海市奉贤区高三二模数学试卷及答案解析
- 医院屋顶光伏施工造价预算方案模板
- 从创意到创业知到智慧树章节测试课后答案2024年秋湖南师范大学
- FZ/T 07008-2020定形机热平衡测试与计算方法
- 被动语态游戏教育课件
- 火花源原子发射光谱分析课件
评论
0/150
提交评论