網(wǎng)絡通信編程技術2_第1頁
網(wǎng)絡通信編程技術2_第2頁
網(wǎng)絡通信編程技術2_第3頁
網(wǎng)絡通信編程技術2_第4頁
網(wǎng)絡通信編程技術2_第5頁
已閱讀5頁,還剩31頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第二章Winsock編程接口Winsock是Windows下網(wǎng)絡編程的標準接口,它允許兩個或多個應用程序在相同機器上,或者是通過網(wǎng)絡相互交流。Winsock是真正的協(xié)議無關的接口,本章主要講述如何使用它來編寫應用層的網(wǎng)絡應用程序。2.1Winsock庫Winsock庫有兩個版本,Winsock1和Winsock2。現(xiàn)在開發(fā)網(wǎng)絡應用程序都使用Winsock2,需要在程序中包含頭文件winsock2.h,它包含了絕大部分socket函數(shù)和相關結構類型的聲明和定義。同時要添加的還有到WS2_32.lib庫的鏈接。包含必要的頭文件,設置好鏈接環(huán)境之后,便可進行下面的編碼工作了。2.1Winsock庫Winsock庫的裝入和釋放每個Winsock應用程序必須加載相應版本的WinsockDLL。如果在調用Winsock函數(shù)前沒有加載Winsock庫,函數(shù)返回SOCKET_ERROR,出錯代碼將是WSANOTINITIALISED。加載Winsock庫的函數(shù)是WSAStartup,其定義如下。intWSAStartup(WORDwVersionRequested,//指定想要加載的Winsock庫的版本,高字節(jié)為次版本號,低字節(jié)為主版本號LPWSADATAlpWSAData//一個指向WSADATA結構的指針,用來返回DLL庫的詳細信息);wVersionRequested參數(shù)用來指定想要加載的Winsock庫的版本。為了建立此參數(shù)的值,可以使用宏MAKEWORD(x,y),其中x是高字節(jié),y是低字節(jié)。lpWSAData是一個指向LPWSADATA結構的指針,WSAStartup使用所加載庫的版本信息填充它。typedefstructWSAData{WORDwVersion;//庫文件建議應用程序使用的版本W(wǎng)ORDwHighVersion;//庫文件支持的最高版本charszDescription[WSADESCRIPTION_LEN+1];//庫描述字符串charszSystemStatus[WSASYS_STATUS_LEN+1];//系統(tǒng)狀態(tài)字符串unsignedshortiMaxSockets;//同時支持的最大套接字的數(shù)量unsignedshortiMaxUdpDg;//2.0版中已廢棄的參數(shù)charFAR*lpVendorInfo;//2.0版中已廢棄的參數(shù)}WSADATA,FAR*LPWSADATA;函數(shù)調用成功返回0。否則要調用WSAGetLastError函數(shù)查看出錯的原因。此函數(shù)的作用相當于API函數(shù)GetLastError,它取得最后發(fā)生錯誤的代碼。每一個對WSAStartup的調用必須對應一個對WSACleanup的調用,這個函數(shù)釋放Winsock庫。intWSACleanup(void);所有的Winsock函數(shù)都是從WS2_32.DLL導出的,VC++在默認情況下并沒有鏈接到該庫,如果想使用WinsockAPI,就必須包含相應的庫文件。#pragmacomment(lib,"WS2_32")2.1.2封裝CInitSock類每次寫網(wǎng)絡程序都必須編寫代碼載入和釋放Winsock庫,為了今后討論方便,這里封裝一個CInitSock類來管理Winsock庫,類的使用方法見下一小節(jié)。#include<winsock2.h>//initsock.h文件#pragmacomment(lib,"WS2_32")//鏈接到WS2_32.libclassCInitSock{public:CInitSock(BYTEminorVer=2,BYTEmajorVer=2){//初始化WS2_32.dllWSADATAwsaData;WORDsockVersion=MAKEWORD(minorVer,majorVer);if(::WSAStartup(sockVersion,&wsaData)!=0){exit(0);}}~CInitSock(){::WSACleanup();}};2.2Winsock的尋址方式和字節(jié)順序因為Winsock要兼容多個協(xié)議,所以必須使用通用的尋址方式。TCP/IP使用IP地址和端口號來指定一個地址,但是其他協(xié)議也許采用不同的形式。如果Winsock強迫使用特定的尋址方式,添加其他協(xié)議就不大可能了。Winsock的第一個版本使用sockaddr結構來解決此問題。structsockaddr

{

u_shortsa_family;charsa_data[14];};2.2Winsock的尋址方式和字節(jié)順序在這個結構中,第一個成員sa_family指定了這個地址使用的地址家族。sa_data成員存儲的數(shù)據(jù)在不同的地址家族中可能不同。本書僅僅使用Internet地址家族(TCP/IP),Winsock已經(jīng)定義了sockaddr結構的TCP/IP版本——sockaddr_in結構。它們本質上是相同的結構,但是第2個更容易操作。在Winsock中,應用程序通過SOCKADDR_IN結構來指定IP地址和端口號,定義如下。structsockaddr_in{shortsin_family;//地址家族(即指定地址格式),應為AF_INETu_shortsin_port;//端口號structin_addrsin_addr;//IP地址charsin_zero[8];//空字節(jié),要設為0};(1)sin_family域必須設為AF_INET,它告訴Winsock程序使用的是IP地址家族。(2)sin_port域指定了TCP或UDP通信服務的端口號。應用程序在選擇端口號時必須小心,因為有一些端口號是保留給公共服務使用的,如FTP和HTTP?;旧?,端口號可分成如下3個范圍:公共的、注冊的、動態(tài)的(或私有的)。z0~1023由IANA(InternetAssignedNumbersAuthority)管理,保留為公共的服務使用。z1024~49151是普通用戶注冊的端口號,由IANA列出。z49152~65535是動態(tài)和/或私有的端口號。2.2Winsock的尋址方式和字節(jié)順序普通用戶應用程序應該選擇1024~49151之間的注冊了的端口號,以避免使用了一個其他應用程序或者系統(tǒng)服務已經(jīng)使用的端口號。在49152~65535之間的端口號也可以自由地使用,因為沒有服務注冊這些端口號。(3)sin_addr域用來存儲IP地址(32位),它被定義為一個聯(lián)合來處理整個32位的值,兩個16位部分或者每個字節(jié)單獨分開。描述32位IP地址的in_addr結構定義如下。structin_addr{union{struct{u_chars_b1,s_b2,s_b3,s_b4;}S_un_b;//以4個u_char來描述struct{u_shorts_w1,s_w2;}S_un_w;//以2個u_short來描述u_longS_addr;//以1個u_long來描述}S_un;};2.2Winsock的尋址方式和字節(jié)順序用字符串“aa.bb.cc.dd”表示IP地址時,字符串中由點分開的4個域是以字符串的形式對in_addr結構中的4個u_char值的描述。由于每個字節(jié)的數(shù)值范圍是0~255,所以各域的值都不可超過255。(4)最后一個域sin_zero沒有使用,是為了與SOCKADDR結構大小相同才設置的。應用程序可以使用inet_addr函數(shù)將一個由小數(shù)點分隔的十進制IP地址字符串轉化成由32位二進制數(shù)表示的IP地址。inet_ntoa是inet_addr函數(shù)的逆函數(shù),它將一個網(wǎng)絡字節(jié)順序的32位IP地址轉化成字符串。unsignedlonginet_addr(constchar*cp);//將一個"aa.bb.cc.dd"類型的IP地址字符串轉化為32位的二進制數(shù)char*inet_ntoa(structin_addrin);//將32位的二進制數(shù)轉化為字符串注意,inet_addr返回的32位二進制數(shù)是用網(wǎng)絡順序存儲的,下一小節(jié)詳細講述字節(jié)順序。2.2Winsock的尋址方式和字節(jié)順序2.2.2字節(jié)順序字節(jié)順序是長度跨越多個字節(jié)的數(shù)據(jù)被存儲的順序。例如,一個32位的長整型0x12345678跨越4個字節(jié)(每個字節(jié)8位)。Intelx86機器使用小尾順序(little-endian),意思是最不重要的字節(jié)首先存儲。因此,數(shù)據(jù)0x12345678在內存中的存放順序是0x78、0x56、0x34、0x12。大多數(shù)不使用小尾順序的機器使用大尾順序(big-endian),即最重要的字節(jié)首先存儲。同樣的值在內存中的存放順序將是0x12、0x34、0x56、0x78。因為協(xié)議數(shù)據(jù)要在這些機器間傳輸,所以就必須選定其中的一種方式做為標準,否則會引起混淆。TCP/IP統(tǒng)一規(guī)定使用大尾方式傳輸數(shù)據(jù),也稱為網(wǎng)絡字節(jié)順序。例如,端口號(它是一個16位的數(shù)字)12345(0x3039)的存儲順序是0x30、0x39。32位的IP地址也是以這種方式存儲的,IP地址的4部分存儲在4個字節(jié)中,第一部分存儲在第一個字節(jié)中。上述sockaddr和sockaddr_in結構中,除了sin_family成員(它不是協(xié)議的一部分)外,其他所有值必須以網(wǎng)絡字節(jié)順序存儲。Winsock提供了一些函數(shù)來處理本地機器的字節(jié)順2.2Winsock的尋址方式和字節(jié)順序2.2.2字節(jié)順序u_shorthtons(u_shorthostshort);//將u_short類型變量從主機字節(jié)順序轉化到TCP/IP網(wǎng)絡字節(jié)順序u_longhtonl(u_longhostlong);//將u_long類型變量從主機字節(jié)順序轉化到TCP/IP網(wǎng)絡字節(jié)順序u_shortntohs(u_shortnetshort);//將u_short類型變量從TCP/IP網(wǎng)絡字節(jié)順序轉化到主機字節(jié)順序u_longntohl(u_longnetlong);//將u_long類型變量從TCP/IP網(wǎng)絡字節(jié)順序轉化到主機字節(jié)順序2.2Winsock的尋址方式和字節(jié)順序初始化sockaddr_in結構sockaddr_insockAddr;//設置地址家族sockAddr.sin_family=AF_INET;//轉化端口號6789到網(wǎng)絡字節(jié)順序,并安排它到正確的成員sockAddr.sin_port=htons(6789);//inet_addr函數(shù)轉化一個"aa.bb.cc.dd"類型的IP地址字符串到長整型,//它是以網(wǎng)絡字節(jié)順序記錄的IP地址sockAddr.sin_addr.S_un.S_addr=inet_addr("");//也可以用下面的代碼設置IP地址(通過設置4個字節(jié)部分,設置sockAddr的地址)/*sockAddr.sin_addr.S_un.S_un_b.s_b1=127;sockAddr.sin_addr.S_un.S_un_b.s_b2=0;sockAddr.sin_addr.S_un.S_un_b.s_b3=0;sockAddr.sin_addr.S_un.S_un_b.s_b4=1;*/2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息通常,主機上的接口被靜態(tài)地指定一個IP地址,或者是由配置協(xié)議來分配,如動態(tài)主機配置協(xié)議(DHCP)。如果DHCP服務器不能到達,系統(tǒng)會使用AutomaticPrivateIPAddressing(APIPA)自動分配/16范圍內的地址。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息1.獲取本機IP地址獲取本機的IP地址比較簡單,下面的GetAllIps例子打印出了本機使用的所有IP(一個適配器一個IP地址),程序代碼如下。#include"../common/InitSock.h"http://GetAllIps工程#include<stdio.h>CInitSockinitSock;//初始化Winsock庫voidmain(){charszHost[256];

//取得本地主機名稱

::gethostname(szHost,256);

//通過主機名得到地址信息

hostent*pHost=::gethostbyname(szHost);

//打印出所有IP地址

in_addraddr;

for(inti=0;;i++)

{char*p=pHost->h_addr_list[i];//p指向一個32位的IP地址

if(p==NULL)break;

memcpy(&addr.S_un.S_addr,p,pHost->h_length);

char*szIp=::inet_ntoa(addr);

printf("本機IP地址:%s\n",szIp);}}GetAllIps先調用gethostname取得本地主機的名稱,然后通過主機名得到其地址信息。2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息有時為了檢測網(wǎng)絡,或者為了一些其他特殊的目的,需要自己來直接操作原始數(shù)據(jù)幀(第9章再具體講述),這就需要獲取自己和LAN中其他主機的MAC地址。獲取本地機器的MAC地址很容易,使用幫助函數(shù)GetAdaptersInfo即可。此函數(shù)的作用是獲取本地機器的適配器信息,用法如下。DWORDGetAdaptersInfo(PIP_ADAPTER_INFOpAdapterInfo,//指向一個緩沖區(qū),用來取得IP_ADAPTER_INFO結構的列表–PULONGpOutBufLen//用來指定上面緩沖區(qū)的大小。如果大小不夠,此參數(shù)返回所需大小);//函數(shù)調用成功返回ERROR_SUCCESSIP_ADAPTER_INFO結構包含了本地計算機上網(wǎng)絡適配器的信息,定義如下。typedefstruct_IP_ADAPTER_INFO{struct_IP_ADAPTER_INFO*Next;//指向適配器列表中的下一個適配器(計算機可能有多個適配器)2.2Winsock的尋址方式和字節(jié)順序2.2.3獲取地址信息程序見LocalhostInfo2.3Winsock編程詳解使用TCP創(chuàng)建網(wǎng)絡應用程序稍微復雜一些,因為TCP是面向連接的協(xié)議,需要通信雙方首先建立一個連接。本節(jié)先以建立簡單的TCP客戶端和服務器端應用程序為例,詳細說明Winsock的編程流程,然后再介紹較為簡單的UDP編程。2.3Winsock編程詳解2.3.1Winsock編程流程1.套接字的創(chuàng)建和關閉使用套接字之前,必須調用socket函數(shù)創(chuàng)建一個套接字對象,此函數(shù)調用成功將返回套接字句柄。SOCKETsocket(intaf,//用來指定套接示使用的地址格式,WinSock中只支持AF_INETinttype,//用來指定套接字的類型intprotocol//配合type參數(shù)使用,用來指定使用的協(xié)議類型。可以是IPPROTO_TCP等);2.3Winsock編程詳解2.3.1Winsock編程流程1.套接字的創(chuàng)建和關閉當type參數(shù)指定為SOCK_STREAM和SOCK_DGRAM時,系統(tǒng)已經(jīng)明確使用TCP和UDP來工作,所以protocol參數(shù)可以指定為0。函數(shù)執(zhí)行失敗返回INVALID_SOCKET(即-1),可以通過調用WSAGetLastError取得錯誤代碼。也可以使用Winsock2的新函數(shù)WSASocket來創(chuàng)建套接字,與socket相比,它提供了更多的參數(shù),如可以自己選擇下層服務提供者、設置重疊標志等,后面再具體討論它。當不使用socket創(chuàng)建的套接字時,應該調用closesocket函數(shù)將它關閉。如果沒有錯誤發(fā)生,函數(shù)返回0,否則返回SOCKET_ERROR。函數(shù)用法如下。intclosesocket(SOCKETs);//函數(shù)惟一的參數(shù)就是要關閉的套接字的句柄2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號bind函數(shù)用在沒有建立連接的套接字上,它的作用是綁定面向連接的或者無連接的套接字。套接字被socket函數(shù)創(chuàng)建以后,存在于指定的地址家族里,但它是未命名的。bind函數(shù)通過安排一個本地名稱到未命名的socket而建立此socket的本地關聯(lián)。本地名稱包含3部分:主機地址、協(xié)議號(分別為UDP或TCP)和端口號。本節(jié)的TCPServer程序使用以下代碼綁定套接字s到本地地址。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號//填充sockaddr_in結構sockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(4567);sin.sin_addr.S_un.S_addr=INADDR_ANY;//綁定這個套接字到一個本地地址if(::bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR){printf("Failedbind()\n");return0;}sockaddr_in結構中的sin_familly字段用來指定地址家族,該字段和socket函數(shù)中的af參數(shù)的含義相同,所以惟一可以使用的值就是AF_INET。sin_port字段和sin_addr字段分別指定套接字需要綁定的端口號和IP地址。放入這兩個字段的數(shù)據(jù)的字節(jié)順序必須是網(wǎng)絡字節(jié)順序。因為網(wǎng)絡字節(jié)順序和IntelCPU的字節(jié)順序剛好相反,所以必須首先使用htons函數(shù)進行轉換。如果應用程序不關心所使用的地址,可以指定Internet地址為INADDR_ANY,指定端口號為0。如果Internet地址等于INADDR_ANY,系統(tǒng)會自動使用當前主機配置的所有IP地址,簡化了程序設計;如果端口號等于0,程序執(zhí)行時系統(tǒng)會為這個應用程序分配惟一的端口號,其值在1024~5000之間。應用程序可以在bind之后使用getsockname來知道為它分配的地址。但是要注意,直到套接字連接上之后getsockname才可能填寫Internet地址,因為對一個主機來說可能有多個地址是可用的。TCP客戶端程序也可以在不顯式綁定地址和端口號的情況下發(fā)送數(shù)據(jù)或者連接。在這種情況下,系統(tǒng)也會默認地為套接字綁定一個本地端口(1024~5000之間)。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設置套接字進入監(jiān)聽狀態(tài)listen函數(shù)設置套接字進入監(jiān)聽狀態(tài)。intlisten(SOCKETs,//套接字句柄intbacklog//監(jiān)聽隊列中允許保持的尚未處理的最大連接數(shù)量);為了接受連接,首先使用socket函數(shù)創(chuàng)建套接字,然后使用bind函數(shù)將它綁定到本地地址,再用listen函數(shù)為到達的連接指定backlog,最后使用accept接受請求的連接。listen僅應用在支持連接的套接字上,如SOCK_STREAM類型的套接字。函數(shù)執(zhí)行成功后,套接字s進入了被動模式,到來的連接會被通知要排隊等候接受處理。在同一時間處理多個連接請求的服務器通常使用listen函數(shù),如果一個連接請求到達,并且排隊已滿,客戶端將接收到WSAECONNREFUSED錯誤。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設置套接字進入監(jiān)聽狀態(tài)4.接受連接請求accept函數(shù)用于接受到來的連接。SOCKETaccept(SOCKETs,//套接字句柄structsockaddr*addr,//一個指向sockaddr_in結構的指針,用于取得對方的地址信息int*addrlen//一個指向地址長度的指針);2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設置套接字進入監(jiān)聽狀態(tài)4.接受連接請求該函數(shù)在s上取出未處理連接中的第一個連接,然后為這個連接創(chuàng)建新的套接字,返回它的句柄。新創(chuàng)建的套接字是處理實際連接的套接字,它與s有相同的屬性。程序默認工作在阻塞模式下,這種方式下如果沒有未處理的連接存在,accept函數(shù)會一直等待下去,直到有新的連接發(fā)生才返回。addrlen參數(shù)用于指定addr所指空間的大小,也用于返回地址的實際長度。如果addr或者addrlen是NULL,則沒有關于遠程地址的信息返回??蛻舳顺绦蛟趧?chuàng)建套接字之后,要使用connect函數(shù)請求與服務器連接,2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號3.設置套接字進入監(jiān)聽狀態(tài)4.接受連接請求5.收發(fā)數(shù)據(jù)對流套接字來說,一般使用send和recv函數(shù)來收發(fā)數(shù)據(jù)。intsend(SOCKETs,//套接字句柄constcharFAR*buf,//要發(fā)送數(shù)據(jù)的緩沖區(qū)地址intlen,//緩沖區(qū)長度intflags//指定了調用方式,通常設位0);intrecv(SOCKETs,charFAR*buf,intlen,int);send函數(shù)在一個連接的套接字上發(fā)送緩沖區(qū)內的數(shù)據(jù),返回發(fā)送數(shù)據(jù)的實際字節(jié)數(shù)。recv函數(shù)從對方接收數(shù)據(jù),并將其存儲到指定的緩沖區(qū)。flags參數(shù)在這兩函數(shù)中通常設為0。在阻塞模式下,send將會阻塞線程的執(zhí)行直到所有的數(shù)據(jù)發(fā)送完畢(或者發(fā)生錯誤),而recv函數(shù)將返回盡可能多的當前可用信息,直到達到緩沖區(qū)指定的大小。2.3Winsock編程詳解2.3.12.綁定套接字到指定的IP地址和端口號2.3.2典型過程圖TCP服務器程序和客戶程序的創(chuàng)建過程如圖2.2所示。服務器端創(chuàng)建監(jiān)聽套接字,并為它關聯(lián)一個本地地址(指定IP地址和端口號),然后進入監(jiān)聽狀態(tài)準備接受客戶的連接請求。為了接受客戶端的連接請求,服務器端必須調用accept函數(shù)??蛻舳藙?chuàng)建套接字后即可調用connect函數(shù)去試圖連接服務器監(jiān)聽套接字。當服務器端的accept函數(shù)返回后,connect函數(shù)也返回。此時客戶端使用socket函數(shù)創(chuàng)建的套接字,服務器端使用accept函數(shù)創(chuàng)建的套接字,雙方就可以通信了。2.3Winsock編程詳解2.3Winsock編程詳解2.3.3TCP服務器和客戶端程序舉例下面是最簡單的TCP服務器程序和TCP客戶端程序的例子。這兩個程序都是控制臺界面的Win32應用程序,分別在配套光盤的TCPServer和TCPClient工程下。運行服務器程序TCPServer,如果沒有錯誤發(fā)生,將在本地機器上的4567端口上等待客戶端的連接。如果沒有連接請求,服務器會一直處于休眠狀態(tài)。運行服務器之后,再運行客戶端程序TCPClient,其最終效果如圖2.3所示。客戶端連接到了服務器,雙方套接字可以通信了。程序見TCPServer2.3Winsock編程詳解2.3.4UDP編程TCP由于可靠、穩(wěn)定的特點而被用在大部分場合,但它對系統(tǒng)資源要求比較高。UDP是一個簡單的面向數(shù)據(jù)報的傳輸層協(xié)議,又叫用戶數(shù)據(jù)報協(xié)議。它提供了無連接的、不可靠的數(shù)據(jù)傳輸服務。無連接是指它不像TCP那樣在通信前先與對方建立連接以確定對方的狀態(tài)。不可靠是指它直接按照指定IP地址和端口號將數(shù)據(jù)包發(fā)出去,如果對方不在線的話數(shù)據(jù)就可能丟失。1.UDP編程流程(1)服務器端程序設計流程如下。①創(chuàng)建套接字(socket)。②綁定IP地址和端口(bind)。③收發(fā)數(shù)據(jù)(sendto/recvfrom)。④關閉連接(closesocket)。(2)客戶端程序設計流程如下。①創(chuàng)建套接字(socket)。②收發(fā)數(shù)據(jù)(sendto/recvfrom)。③關閉連接(closesocket)。UDP用于發(fā)送和接收數(shù)據(jù)的函數(shù)是sendto和recvfrom,它們的用法如下。同樣,UDP接收數(shù)據(jù)時也需要知道通信對端的地址信息。intrecvfrom(SOCKETs,charFAR*buf,intlen,intflags,structsockaddrFAR*from,intFAR*fromlen);這個函數(shù)比recv函數(shù)多出

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論