




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、精品文档FTP协议实验报告实验目的1、在Linux系统上完成一个文件传输协议(FTP)的简单实现。2、深入理解FTP协议的原理和协议细节。3、学会利用 Socket 接口设计实现简单应用层协议。4、掌握TCP/IP网络应用程序的基本设计方法和实现技巧。实验原理1、FTP协议FTP是File Transfer Protocol,即文件传输协议的缩写。该协议用于在两台计算机之间传 送文件。FTP会话包括了两个通道,一个是控制通道,一个是数据通道。控制通道是和FTP服务器进行沟通的通道, 连接FTP服务器,发送FTP指令;数据通道则是和FTP服务器进行 文件传输或者获取文件列表的通道。FTP协议中,
2、控制连接的各种指令均由客户端主动发起,而数据连接有两种工作方式: 主动方式(PORT方式)和被动方式(PASV方式)。主动方式下,FTP客户端首先和 FTP服务器的控制通道对应端口(一般为 21)建立连接,通过控制通道发送命令,客户端需要接 收数据的时候在这个通道上发送 PORT命令。PORT命令包含了客户端用什么端口(一个大 于1024的端口)接收数据。在传输数据的时候,FTP服务器必须和客户端建立一个新的连接,服务器通过自己的 TCP 20 端口发送数据。被动方式下,建立控制通道的过程和主动方 式类似,当客户端通过这个通道发送PASV命令的时候,FTP server打开一个位于1024-5
3、000之间的随机端口并且通知客户端,然后客户端与服务器之间将通过这个端口进行数据的传 送。2 、 socket 编程( 1 )什么是 SocketSocket接口是TCP/IP网络的API, Socket接口定义了许多函数或例程。网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。(2)Socket的建立为了建立 Socket,程序可以调用 Socket函数,该函数返回一个socket描述符。Socket描述符是一个指向内部数据结构的指针,它指向描述符表入口。调用Socket函数时,socket执行体将建立一个 Socket,实际上”建立一个Socket"意
4、味着为一个Socket数据结构分配存储 空间。Socket执行体为你管理描述符表。两个网络程序之间的一个网络连接包括五种信息: 通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。Socket数据结构中包含这五种信息。socket 函数原型为: int socket(int domain, int type, int protocol);domain :指明所使用的协议族,通常为PF_INET表示互联网协议族(TCP/IP协议族);type :指定 socket 的类型为 SOCK_STREAM或 SOCK_DGRAMSocket接口还定义了原始 Socket(SOCK_RAV)
5、允许程序使用低层协议;protocol :通常赋值 "0" 。 返回:整型socket描述符。( 3) Socket 配置无连接 socket 的客户端和服务端以及面向连接 socket 的服务端通过调用 bind 函数来 配置本地信息。Bind 函数将 socket 与本机上的一个端口相关联,随后你就可以在该端口监听服务请求。Bind 函数原型为: int bind(int sockfd,struct sockaddr_in *my_addr, int addrlen);Sockfd:调用socket函数返回的socket描述符my_addr: 个指向包含有本机IP地址及
6、端口号等信息的sockaddr类型的指针addrlen :常被设置为 sizeof(struct sockaddr)。struct sockaddr_in 结构类型是用来保存 socket 信息的:struct sockaddr_in short int sin_family; /* 地址族 */unsigned short int sin_port; /* 端口号 */struct in_addr sin_addr; /* IP 地址 */unsigned char sin_zero8; /* 填充 0 以保持与 struct sockaddr 同样大小 */;sin_zero:用来将 so
7、ckaddrn结构填充到与 struct sockaddr同样的长度,可以用 bzero()或 memset() 函数将其置为零。使用bind函数时,可以用下面的赋值实现自动获得本机IP地址和随机获取一个没有被占用的端口号:my_addr.sin_port = 0; /* 系统随机选择一个未被使用的端口号 */my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机 IP 地址 */通过将 my_addr.sin_port 置为 0,函数会自动为你选择一个未占用的端口来使用。同样,通过将 my_addr.sin_addr.s_addr置为INADDR_ANY
8、系统会自动填入本机IP地址。Bind()函数在成功被调用时返回0;出现错误时返回"-1"并将errno置为相应的错误号。需要注意的是,在调用 bind 函数时一般不要将端口号置为小于 1024的值,因为 1到1024 是保留端口号,你可以选择大于 1024中的任何一个没有被占用的端口号。(4) 连接建立无连接协议从不建立直接连接。 面向连接的服务器也从不启动一个连接, 它只是被动的 在协议端口监听客户的请求。Listen函数使socket处于被动的监听模式,并为该socket建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程序处理它们。int listen(int
9、 sockfd , int backlog);Sockfd: Socket系统调用返回的 socket描述符backlog :指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待accept()。如果一个服务请求到来时,输入队列已满,该 socket 将拒绝连接请求,客户将收到一个出 错信息。返回:当出现错误时 listen 函数返回 -1 ,并置相应的 errno 错误码。accept()函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用accept函数,然后睡眠并等待客户的连接请求。int accept(int sockfd, void *addr, int *ad
10、drlen);sockfd :被监听的socket描述符;addr:通常是一个指向sockaddr_in变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求) ;addrten :通常为一个指向值为 sizeof(struct sockaddr_in) 的整型指针变量;返回:出现错误时 accept 函数返回 -1 并置相应的 errno 值。(5 )结束传输当所有的数据操作结束以后,你可以调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:close(sockfd);实验内容在Linux系统上使用Socket接口实现FTP客户
11、端 和服务器的程序,使客户端可以连接 至服务器,并且可以进行一些FTP的基本操作,如列出目录、下载文件等。从FTP协议的实现角度来看,客户端与服务器的命令通道和数据通道需要分享,同时应该支持以下一些FTP命令:get:取远方的一个文件。 put:传给远方一个文件。 pwd :显示远方当前目录。 dir:列出远方当前目录。 cd:改变远方当前目录。?:显示你提供的命令quit :退出返回实验过程1、实现服务器端(1 )全局变量为了记录缓冲区大小、当前目录、当前工作路径、帮助信息而定义了以下几个全局变量:(2)函数在服务器端实现了以下几个函数:char *getDirName(char *dirP
12、athName);voidcmd_pwd intsock);voidcmd_dir (intsock);voidcmd_cd( intsock,char *dirName);voidcmd_help( intsock);voidcmd_get( intsock,char''fileName 'voidcmd_put( intsock,char* fileName/根据当前工作目录的绝对路径得到当前目录名称/处理pwd命令/处理dir命令/处理cd命令/处理?命令/处理get命令/处理put命令#define dataLen 1024/缓冲区大小charcurrentDi
13、rPath 200;/当前工作目录的绝对路径charcurrentDirName 30;/当前目录的名称charhelp = "getget a file from servernputupload a file to servernpwddisplay the current directory of serverndirdisplay the files in the current directory of serverncdchange the directory of servern?display the whole command which equals 'h
14、elp'nquitreturnn"/帮助信息精品文档(3 )主函数的实现:先建立数据通道和命令通道,然后监听,若有客户端连上,则建立一个子进程,先向客户端发送帮助信息,然后根据客户端的命令来调用上述各函数来处理。int main(int argc , char * argv )int sock;/服务器用于监听的数据通道int sockmsg;/服务器用于监听的命令通道char client_cmd 10;/客户端岀发的命令char cmd_arg20;/客户端输入的文件或目录名,用在cd,put,get 命令中struct sockaddr_in server ;/服务器数
15、据通道的信息struct sockaddr_in servermsg ;/服务器命令通道的信息int datasock ;/用于通信的数据通道int msgsock;/用于通信的命令通道pid_t child ;/client 子进程sock=socket (AF_INET, SOCK_STREAM/创建用于传数据的套接字sockmsg=socket (AF_INET, SOCK_STREAM/创建用于传消息的套接字int opt = 1, opt2 = 1;setsockopt (sock , SOL_SOCKE,T SO_REUSEADDR opt , sizeof (opt);/实现so
16、ck的重用setsockopt (sockmsg , SOL_SOCKE,T SO_REUSEADDR opt2 , sizeof (opt2 ); /实现sockmsg的重用if ( sock < 0 | sockmsg < 0)/socket创建失败perror ("opening stream socket");exit (1);memse(&server ,0, sizeof (server );server . sin_family =AF_INET/设置协议族server . sin_addr . s_addr =htonl (INADDR_
17、ANJY/监听所有地址server . sin_port =htons (45000);/端口设为45000memse(&servermsg ,0, sizeof (servermsg );servermsg . sin_family =AF_INET/设置协议族servermsg . sin_addr . s_addr =htonl (INADDR_ANJY/监听所有地址servermsg . sin_port =htons (45001);/端口设为45001if ( bind (sock,( struct sockaddr *) & server , sizeof ( s
18、erver ) < 0 |bind (sockmsg, ( structsockaddr *) & servermsg , sizeof (servermsg ) <0)/连接不成功perror ("binding stream socket");exit (1);int length = sizeof (server );int lengthmsg = sizeof (servermsg );if ( getsockname(sock,( struct sockaddr *) & server,&Iength ) < 0 | ge
19、tsockname(sockmsg,( struct sockaddr *) & servermsg ,&lengthmsg ) < 0)/ 得至U套接字的本地名字perror ("getting socket name" );exit (1);printf ("Socket port # %d %dn", ntohs (server . sin_port ), ntohs ( servermsg . sin_port );memse(currentDirPath ,0, sizeof (currentDirPath );getcw
20、d (currentDirPath , sizeof ( currentDirPath ); / 将当前工作目录的绝对路径复制到 /currentDirPath 中/监听数据通道/监听命令通道listen (sock ,2);listen (sockmsg,2);while (1)/与客户端的数据通道连接/与客户端的命令通道连接/岀错/子进程);datasock = accept ( sock,( struct sockaddr *)0,( int *)0); msgsock = accept (sockmsg,( struct sockaddr *)0,( int *)0); if ( da
21、tasock = -1 | msgsock=-1)perror ("accept");else if ( child = fork () = -1)printf ("Fork Error!n" );if (child = 0)printf ("connection accepted! new client comingn" write (datasock , help , strlen ( help ) + 1);loop :memse( client_cmd ,0, sizeof (client_cmd );int rval = 0
22、;rval = read (msgsock, client_cmd , sizeof (client_cmd ); / 读命令 printf ("%dn", rval );if (rval < 0)perror ("reading command failedn" );else if (rval = 0)/ 连接关闭printf ("connection closed.n" );close (datasock );close (msgsock);else if (strcmp ( client_cmd , "pwd&q
23、uot;) = 0)/ 为 pwc命令printf ("command pwdn");cmd_pwQ datasock );printf ("donenn");goto loop ;else elseelse else else else elseif ( strcmp (client_cmd , "dir" ) = 0) printf ("command dirn");cmd_dir (datasock );printf ("donenn");goto loop ;if ( strcmp (c
24、lient_cmd , "cd" ) = 0)printf ("command cdn");memse( cmd_arg,0, sizeof ( cmd_arg); read (msgsock, cmd_arg, sizeof ( cmd_arg); cmd_cd( datasock , cmd_arg);printf ("donenn");goto loop ;if ( strcmp (client_cmd , "get" ) = 0) printf ("command getn");mems
25、e( cmd_arg,0, sizeof ( cmd_arg); read (msgsock, cmd_arg, sizeof ( cmd_arg); cmd_get( datasock , cmd_arg);printf ("donenn");goto loop ;if ( strcmp (client_cmd , "put" ) = 0) printf ("command putn");memse( cmd_arg,0, sizeof ( cmd_arg); read (msgsock, cmd_arg, sizeof ( cmd
26、_arg); cmd_put( datasock , cmd_arg);printf ("donenn");goto loop ;if ( strcmp (client_cmd , "?") = 0) printf ("command ?n");cmd_help(datasock );printf ("donenn");goto loop ;if ( strcmp (client_cmd , "quit" ) = 0) printf ("quitn");goto endchi
27、ld ;printf ("bad requestin'');goto loop ;/为dir命令/为cd命令/为get命令/为put命令/为?命令/为quit命令/错误的命令endchild :/客户退出printf ("connection closed.'n" );close (datasock );close (msgsock);exit (1);exit (0);(4) char * getDirName ( char * dirPathName )的实现:由当前工作目录的绝对地址得到当前工作目录的名称,当前工作目录的名称是绝对地址
28、中最后一个“ /”号之后的字符串,通过从后向前遍历绝对地址字符串找到最后一个“/然后再取其后的字符串即可得到当前工作目录的名称。*getDirName得到当前工作目录名称*dirPathName 当前工作目录的绝对地址*输岀:当前工作目录名称*/char * getDirName (char * dirPathName)int i , pos, len ;char * dirName;/当前工作目录名称if (dirPathName = NULI)printf ("directory absoultly path is null!n");return NULLlen =st
29、rlen (dirPathName);for (i = len - 1; i >= 0; i -)/找到最后一个/号,之后的字符串即为当前工作目录名称if (dirPathName i = '/' )pos=i ;break ;dirName = ( char *) malloc (len - pos + 1);for (i = pos + 1; i <= len ; i +)dirName i - pos - 1 = dirPathName i ;return dirName;(5) void cmd_pwc( int sock)的实现:调用getDirName函
30、数来得到当前工作目录名称,然后发到客户端void cmd_pwQint sock)int len ;char * savePointer = getDirName ( currentDirPath ); / 得到当前工作目录名称strcpy (currentDirName , savePointer );len = strlen ( currentDirName ) + 1;write ( sock, currentDirName , len );/发到客户端(6) void cmd_dir (int sock)的实现:先遍历当前目录下的所有文件及子目录,得到文件及目录数,把该数目发给客户端后
31、, 再一次遍历当前目录下的所有文件及子目录,把文件或目录的名称及信息发给客户端。void cmd_dir (int sock)DIR * pdir ;char fileinfo 50;int i , fcounts = 0, len ;struct dirent * pent;int fd ;struct stat fileSta ;char filePath 200;pdir = opendir (currentDirPath );while ( pent = readdir (pdir )!=NULl)/ 计算文件及目录数fcounts +;write ( sock,&fcount
32、s , sizeof (int );closedir (pdir );if (fcounts <= 0)return ;else pdir =opendir (currentDirPath );for (i = 0; i < fcounts ; i +)pent = readdir (pdir );memse1(fileinfo ,0, sizeof (fileinfo );char * fileName = pent->d_namememse(filePath ,0, sizeof (filePath );strcpy (filePath , currentDirPath
33、);strcat (filePath ,"/");strcat (filePath , fileName );fd = open(filePath , O_RDONLYS_IREAD;);.st_mode) /检查是否为目录,"dirt");,fileName );,"filet" );,fileName );,sizeof (fileinfo );fstat (fd,&fileSta if (S_ISDIR(fileSta strcat (fileinfo strcat (fileinfoelsestrcat (filein
34、fo strcat (fileinfowrite (sock, fileinfoclosedir (pdir );(7) void cmd_cd(int sock, char * dirName)的实现:遍历当前目录查看是否有与客户输入的目录名相同的目录,这里要区分普通目录和上一级目录(即.),若为普通目录则直接在存放当前目录绝对地址的字符串的后面加上新进的目录,若为上一级目录,则要在存放当前目录绝对地址的字符串中删去最后一个目录,即最后一个“ /”号之后的内容。void cmd_cd( int sock, char * dirName)DIR * pdir ;struct dirent *
35、pent;char filename 30;int i , fcounts =0;int flag =0;pdir =opendir ( currentDirPath );pent =readdir ( pdir );while ( pent !=NULLfcounts +;pent =readdir (pdir );closedir (pdir );if (fcounts <=0)return ;else pdir =opendir (currentDirPath );for (i =0; i <fcounts ; i +)pent =readdir ( pdir );if (s
36、trcmp (pent ->d_name dirName )=0)if ( strcmp (dirName,"." ) = 0) int i , pos = 0;int len =strlen (currentDirPath );for (i = len - 1; i >= 0; i -)if ( currentDirPath i ='/' )pos=i ;break ;currentDirPath pos='0 ;else strcat (currentDirPath,"/");strcat (currentDirP
37、ath, dirName);char * savePointer = getDirName ( currentDirPath );strcpy ( currentDirName , savePointer );flag =1;break;if (flag =1)write (sock, currentDirPath , sizeof (currentDirPath );closedir (pdir );(8) void cmd help (intsock)的实现:把存有帮助信息的字符串发到客户端void cmd_help( int sock)int len =strlen (help )+1;
38、write ( sock, help , len );(9) void cmd_get(int sock, char *fileName )的实现:把文件内容一部分一部分地读到缓冲区,然后发给客户端void cmd_get( intsock, char *fileName )int fd ;struct statfileStalong fileSizechar filePath200, buf dataLen ;memse(filePath,0, sizeof (filePath );strcpy (filePath,currentDirPath );strcat (filePath,&quo
39、t;/");strcat (filePath,fileName );fd =open( filePath , O_RDONLYS_IREAD;if (fd ! = -1)fstat (fd,&fileSta );fileSize =(long) fileSta . st_size ; write (sock,&fileSize ,sizeof (long ); memse( buf ,0, dataLen );while (fileSize > dataLen )read (fd , buf, dataLen ); write (sock, buf, dataL
40、en ); fileSize =fileSize - dataLen;read (fd , buf, fileSize );write ( sock, buf, fileSize );close (fd );printf ("transfer completed'"');elseprintf ("open file %s failed'n" , filePath );(10) void cmd_put( intsock, char * fileName )的实现:从客户端一部分一部分地读文件到续冲区,然后写入文件。void cmd
41、_put( int sock, char * fileName )int fd ;long fileSize;char filePath 200,buf dataLen ;strcpy(filePath, currentDirPath);strcat(filePath,"/");strcat(filePath, fileName );fd =open( filePath , 0_RDVyO_CREAT S_IREAD S_IWRITE; if (fd !=-1)memse( buf ,0, dataLen );read (sock,&fileSize , sizeo
42、f (long );while (fileSize >dataLen )read ( sock, buf, dataLen );write (fd , buf, dataLen ); fileSize =fileSize - dataLen;read (sock, buf, fileSize );write (fd , buf , fileSize );close (fd );printf ("transfer completed'"');elseprintf ("open file %s failed'n" , fileP
43、ath );2、客户端的实现(1 )全局变量#define dataLen 1024/缓冲区大小char user_cmd10;/客户端岀发的命令char cmd_arg20;/客户端输入的文件或目录名char buf dataLen ;/缓冲区(2)函数voidcmd_pwd intsock, intsockmsg);voidcmd_dir (intsock, intsockmsg);voidcmd_cd( intsock, int :sockmsg, char *dirName);voidcmd_help( intsock, intsockmsg);voidcmd_get( intsock
44、, intsockmsg, char* fileName );voidcmd_put( intsock, intsockmsg, char* fileName );voidcmd_quit (intsock, intsockmsg);/处理pwd命令/处理dir命令/处理cd命令/处理?命令/处理get命令 /处理put命令/处理put命令(3 )主函数的实现:先与服务器端建立连接,然后处理向服务客端发送的各种命令。int main( int argc , char * argv )int cmd_len, arg_len ;int sock, sockmsg;struct sockaddr_
45、in server , servermsg;struct hostent * hp;sock = socket (AF_INET, SOCK_STREAMsockmsg = socket (AF_INET SOCK_STREAMif ( sock < 0 | sockmsg < 0)perror ("opening stream socket" );exit (1);if (argc != 3)printf ("Usage:./client <address> <port>n");return 0;server . s
46、in_family =AF_INETserver . sin_port =htons (atoi ( argv 2);inet_pton (AFNET, argv 1,& server . sin_addr );servermsg . sin_family =AFNETservermsg . sin_port =htons ( atoi (argv 2) + 1); inet_pton (AFNET, argv 1,& servermsg . sin_addr );if ( connect (sock,( struct sockaddr *)& server , siz
47、eof server )<0| connect (sockmsg,( struct sockaddr *)& servermsg , sizeof servermsg )<0)perror ("connecting stream socket" );exit (1);char help 300;read ( sock, help ,300);printf ("%sn" , help );while (1)memse( user_cmd ,0,10);memse( cmd_arg,0,20);printf ("command:
48、");scanf ("%s", user_cmd);cmd_len = strlen (user_cmd);if (strcmp ( user_cmd, "quit" ) = 0) / quit 命令cmd_quit (sock, sockmsg);close (sockmsg);close (sock);printf ("connection closednn" );exit (0);else if ( strcmp (user_cmd,"?" )=0)/?命令cmd_help(sock, sockms
49、g);else if ( strcmp (user_cmd, "pwd" )=0)pwd 命令cmd_pwd sock, sockmsg);else if (strcmp (user_cmd, "dir" )=0) /dir 命令cmd_dir ( sock, sockmsg);else if ( strcmp (user_cmd, "cd" )=0) / cd 命令scanf ("%s", cmd_arg);cmd_cc( sock, sockmsg, cmd_arg);else if ( strcmp (use
50、r_cmd, "get" )=0) /get 命令scanf ("%s", cmd_arg); cmd_get( sock, sockmsg, cmd_arg);else if ( strcmp (user_cmd, "put" )=0) / put 命令scanf ("%s", cmd_arg);cmd_put( sock, sockmsg, cmd_arg);elseprintf ("bad command!n");(4) void cmd_pwc(int sock, int sockmsg
51、)的实现:向服务器发出pwd命令,然后接收服务器端发来的当前目录名称,并把它打印出来。 void cmd_pwQint sock, int sockmsg)char dirName30;write ( sockmsg, user_cmd, sizeof (user_cmd);read (sock, dirName,30);printf ("%sn" , dirName);(5) void cmd_dir (int sock, int sockmsg)的实现:向服务器发出dir命令,然后接收服务器发来的文件及目录数目,打印出来,接着依次 接收服务器发来的文件或目录信息,打印出
52、来。void cmd_dir (int sock, int sockmsg)int i , fileNum =0;char fileInfo 50;write ( sockmsg, user_cmd, sizeof (user_cmd);read (sock,&fileNum , sizeof (int );printf ("n");printf ("file number : %dn", fileNum );if (fileNum > 0)for (i =0; i <fileNum ; i +)memse1(fileInfo,0,
53、sizeof (fileInfo );read ( sock, fileInfo , sizeof (fileInfo );printf ("%sn" , fileInfo );printf ("n");else if (fileNum = 0)printf ("directory of server point is empty.n");return ;else printf ("error in command 'dir'n" );return ;(6) void cmd_cd(int sock
54、, int sockmsg, char * dirName)的实现: 向服务器发出cd命令,并把目录名传过去,然后接收当前路径,并打印出来。void cmd_cd( int sock, int sockmsg, char * dirName)char currentDirPath 200;write ( sockmsg, user_cmd, sizeof (user_cmd);write ( sockmsg, cmd_arg, sizeof ( cmd_arg);read (sock, currentDirPath , sizeof (currentDirPath );printf (&quo
55、t;now in directory : %sn", currentDirPath );(7) void cmd_help (int sock, int sockmsg)的实现: 向服务器发出?命令,然后接收服务器发来的帮助信息。void cmd_help(int sock, int sockmsg)char help 300;write ( sockmsg, user_cmd, sizeof (user_cmd);read (sock, help ,300);printf ("%sn" , help);(8) void cmd_get(int sock, int
56、 sockmsg, char * fileName )的实现:把get命令和文件名发到服务器,然后一部分一部分地接收服务器发来的字节流,缓存 到缓冲区,然后写到本地文件中。void cmd_get( int sock, int sockmsg,char * fileName )int fd ;long fileSize ;200;char localFilePathwrite (sockmsg, user_cmd, sizeof (user_cmd);write (sockmsg, cmd_arg, sizeof (cmd_arg);printf ("%sn%sn",user_cmd, cmd_arg);memse( localFilePath,0, sizeof (localFilePath );getcwd (localFilePath
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- T/CPFIA 0003-2022含矿物源黄腐酸钾磷酸一铵
- T/CHES 117-2023城市河湖底泥污染状况调查评价技术导则
- T/CI 317-2024药食同源及药膳配方食品生产加工技术规范
- T/ZSX 4-2024社区社会组织培育发展导则
- 贷款延期还款协议书5篇
- 软件园楼房改造vrv空调设备安装合同4篇
- 05-12-27交通指示制作合同3篇
- 公司股权质押解除合同6篇
- 餐饮行业员工用工合同5篇
- 饮食店合同5篇
- 抗凝药术前停用的指南
- ISO28000:2022供应链安全管理体系
- DB22-T 5118-2022 建筑工程资料管理标准
- 集体备课《发生在肺内的气体交换》
- 六年级下册生命生态安全知识要点
- JJG 211-2021 亮度计检定规程(高清最新版)
- 高压喷射注浆工程施工工艺标准
- 最新部编版九年级语文下册课件(完美版)写作布局谋篇
- 个人公证委托书
- 农村水电站岗位设置及定员标准(全面)
- 第五章溶胶凝胶法
评论
0/150
提交评论