版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、Tcp套接字編程知識(shí)點(diǎn): 使用TCP套接字編程的基本步驟 實(shí)現(xiàn)TCP套接字編程的基本函數(shù) 服務(wù)器的3種異常情況TCP套接字編程(cont.)#include int socket(int family, int type, int protocol) 返回:非負(fù)套接字(sockfd)成功;-1出錯(cuò)。功能:指定協(xié)議類型功能:指定協(xié)議類型參數(shù)說明:參數(shù)說明:family:協(xié)議族;type:套接字類型; protocol:一般為0,除原始套接字外。 family typeAF_INET IPv4協(xié)議SOCK_STREAM 字節(jié)流套接口AF_INET6IPv6協(xié)議SOCK_DGRAM 數(shù)據(jù)報(bào)套接口AF
2、_LOCALunix域協(xié)議SOCK_RAW 原始套接口AF_ROUTE 路由套接口AF_KEY 密鑰套接口基本套接字函數(shù)socket AF_INET AF_INET6 AF_LOCAL AF_ROUTE AF_KEY SOCK_STREAM TCP TCP Yes SOCK_DGRAM UDP UDP Yes SOCK_RAW IPv4 IPv6 Yes Yes Protocol:指明此socket請(qǐng)求所使用的協(xié)議,可以使用如下相關(guān)符號(hào)常數(shù)來表示。IPPROTO_TCP:表示TCP協(xié)議IPPROTO_UDP:表示UDP協(xié)議調(diào)用Socket()函數(shù)的過程socket 函數(shù)指定了協(xié)議族函數(shù)指定了協(xié)
3、議族(IPv4、IPv6或或unix)和套接口類型和套接口類型(字節(jié)流、數(shù)據(jù)報(bào)或原字節(jié)流、數(shù)據(jù)報(bào)或原始套接口始套接口)。但并沒有指定本地協(xié)議地址或遠(yuǎn)程協(xié)議地址。但并沒有指定本地協(xié)議地址或遠(yuǎn)程協(xié)議地址。理解理解socket socket使用 Unix 文件描述符 (file descriptor) 和其他程序通訊的方式。 Unix 程序在執(zhí)行任何形式的 I/O 的時(shí)候,程序是在讀或者寫一個(gè)文件描述符。一個(gè)文件描述符只是一個(gè)和打開的文件相關(guān)聯(lián)的整數(shù)。這個(gè)文件可能是一個(gè)網(wǎng)絡(luò)連接,F(xiàn)IFO,管道,終端,磁盤上的文件或者什么其他的東西。Unix 中所有的東西是文件!因此,與 Internet 上別的程序
4、通訊的時(shí)候,要通過文件描述符。 利用系統(tǒng)調(diào)用 socket()得到網(wǎng)絡(luò)通訊的文件描述符。他返回套接口描述符 (socket descriptor),然后再通過他來調(diào)用 send() 和 recv()。那么為什么不用一般的調(diào)用那么為什么不用一般的調(diào)用 read() 和和 write() 來通過套接口通訊?來通過套接口通訊? 簡(jiǎn)單的答案是:可以使用一般的函數(shù)! 詳細(xì)的答案是:使用 send() 和 recv() 讓你更好的控制數(shù)據(jù)傳輸。#include #include int bind(int sockfd, const struct sockaddr *addr, socklen_len ad
5、drlen) 返回:0成功;-1出錯(cuò)并置errno功能:給套接口分配一個(gè)本地協(xié)議地址。功能:給套接口分配一個(gè)本地協(xié)議地址。參數(shù)說明:參數(shù)說明: sockfd是套接字函數(shù)返回的套接字描述符;addr參數(shù)是指向特定協(xié)議的地址結(jié)構(gòu)的指針,指定用于通信的本地協(xié)議地址,這是通用地址(網(wǎng)際協(xié)議)。 addrlen是該套接字地址結(jié)構(gòu)的長(zhǎng)度。 該函數(shù)指明套接字將使用本地的哪一個(gè)協(xié)議端口進(jìn)行數(shù)據(jù)傳送(IP地址和端口號(hào))。 一般而言,服務(wù)器調(diào)用此函數(shù),而客戶則很少調(diào)用它。 基本套接字函數(shù)bind 綁定地址時(shí),可以指定地址和端口號(hào),也可以指定其中之一,甚至一個(gè)也不指定。通配地址:INADDR_ANY,其值一般為0,
6、它通知內(nèi)核選擇IP地址。 若指定端口號(hào)為0,調(diào)用函數(shù)bind時(shí),內(nèi)核選擇一個(gè)臨時(shí)端口(在實(shí)際中,端口號(hào)都要指定);但若指定一個(gè)通配IP地址,則直到套接字已連接(TCP)或數(shù)據(jù)報(bào)已在套接字上發(fā)出(UDP),內(nèi)核才選擇一個(gè)本地IP地址。 表中給出了調(diào)用bind()函數(shù)時(shí),IP地址和端口號(hào)的取值及其對(duì)應(yīng)的結(jié)果。IP地址地址 端口端口結(jié)果結(jié)果通配地址 0內(nèi)核選擇IP地址和端口號(hào)通配地址 非0內(nèi)核選擇IP地址,進(jìn)程指定端口本地IP 0進(jìn)程指定IP地址,內(nèi)核選擇端口本地IP 非0進(jìn)程指定IP地址和端口號(hào)struct sockaddr_in addr;int port = 1234;int opt = SO
7、_REUSEADDR;setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt); bzero(&server,sizeof(server);addr.sin_family = AF_INET;addr.sin_addr.s_addr = htonl(INADDR_ANY);addr.sin_port = htons(port);if (bind(fd, (struct sockaddr *)&addr, sizeof(addr) = -1)/* 錯(cuò)誤處理 */bind函數(shù)的用法#include int list
8、en(int sockfd, int backlog) 返回:0成功;-1出錯(cuò)并置errno值;功能:將未連接主動(dòng)套接口的轉(zhuǎn)換為被動(dòng)套接口,指示內(nèi)核接受功能:將未連接主動(dòng)套接口的轉(zhuǎn)換為被動(dòng)套接口,指示內(nèi)核接受對(duì)該套接口的連接請(qǐng)求對(duì)該套接口的連接請(qǐng)求.函數(shù)listen僅被服務(wù)器調(diào)用,它完成兩件事情: 函數(shù)listen將未連接的套接字轉(zhuǎn)化成被動(dòng)套接字,指示內(nèi)核應(yīng)接受指向此套接字的連接請(qǐng)求; 函數(shù)的第二個(gè)參數(shù)規(guī)定了內(nèi)核為此套接字排隊(duì)的最大連接個(gè)數(shù);基本套接字函數(shù)listen三路握手過程客戶服務(wù)器Connect調(diào)用在未完成隊(duì)列建立條目SYN JSYN K, ack J+1ack K+1該條目從未完成隊(duì)
9、列移至已完成隊(duì)列,accept阻塞Connect返回TCP三路握手和監(jiān)聽套接口的兩個(gè)隊(duì)列對(duì)于給定的監(jiān)聽套接字,內(nèi)核要維護(hù)兩個(gè)隊(duì)列: 未完成連接隊(duì)列:為每個(gè)請(qǐng)求建立連接的SYN分節(jié)開設(shè)一個(gè)條目,服務(wù)器正等待完成TCP三次握手,當(dāng)前的套接字處在SYNRCVD狀態(tài); 已完成連接隊(duì)列:為每個(gè)已完成TCP三次握手的客戶端開設(shè)一個(gè)條目。當(dāng)前的套接字狀態(tài)為ESTABLISHED。 兩個(gè)隊(duì)列之和不超過backlog;三路握手完成兩隊(duì)列之和不能超過backlog已完成連接隊(duì)列(ESTABLISHED狀態(tài))未完成連接隊(duì)列(SYN_RCVD狀態(tài))新到達(dá)的SYN分節(jié)服務(wù)器TCPacceptTCP為監(jiān)聽套接口維護(hù)的兩個(gè)
10、隊(duì)列為監(jiān)聽套接口維護(hù)的兩個(gè)隊(duì)列另外幾點(diǎn)說明:另外幾點(diǎn)說明: 不同的實(shí)現(xiàn)對(duì)backlog有不同的解釋,如源自Berkeley的實(shí)現(xiàn)將backlog增加一個(gè)模糊因子,把它乘以1.5,再作為兩個(gè)隊(duì)列之和; 不要把backlog定義為0,因?yàn)橛行?shí)現(xiàn)允許1個(gè)連接排隊(duì),而有些實(shí)現(xiàn)不允許有連接排隊(duì); 當(dāng)一個(gè)客戶SYN到達(dá)時(shí),若兩個(gè)隊(duì)列都是滿的,tcp就忽略此分節(jié),且不發(fā)送RST。這是因?yàn)?,這種情況是暫時(shí)的,客戶tcp將重發(fā)SYN,期望不久的將來就能在隊(duì)列中找到空閑條目。#include #include int connect(int sockfd, const struct sockaddr *addr
11、, socklen_t addrlen); 返回:0成功;-1出錯(cuò);功能:建立與功能:建立與TCP服務(wù)器的連接服務(wù)器的連接參數(shù)說明:參數(shù)說明:/sockfd 是系統(tǒng)調(diào)用 socket() 返回的套接口文件描述符/serv_addr 是保存著目的地端口和 IP 地址的數(shù)據(jù)結(jié)構(gòu) struct sockaddr/addrlen 設(shè)置為 sizeof(struct sockaddr) 函數(shù)connect激發(fā)TCP的三路握手過程;僅在成功或出錯(cuò)返回;基本套接字函數(shù)connect錯(cuò)誤有以下幾種情況錯(cuò)誤有以下幾種情況: 如果客戶沒有收到SYN分節(jié)的響應(yīng)(總共75秒,這之間需要可能需要重發(fā)若干次SYN),則返
12、回ETIMEDOUT。 如果對(duì)客戶的SYN的響應(yīng)是RST,則表明該服務(wù)器主機(jī)在指定的端口上沒有進(jìn)程在等待與之相連。函數(shù)返回錯(cuò)誤ECONNREFUSED; 如果客戶發(fā)出的SYN在中間路由器上引發(fā)一個(gè)目的地不可達(dá)ICMP錯(cuò)誤,客戶上的內(nèi)核保存此消息,并按第一種情況,連續(xù)發(fā)送SYN,直到規(guī)定時(shí)間,返回保存的消息(即ICMP錯(cuò)誤)作為EHOSTUNREACH或ENETUNREACH錯(cuò)誤返回給進(jìn)程。#include int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen); 返回:非負(fù)描述字(connfd)OK;-1出錯(cuò);功
13、能功能:在已完成隊(duì)列頭返回下一個(gè)已完成的連接。在已完成隊(duì)列頭返回下一個(gè)已完成的連接。 accept函數(shù)由TCP服務(wù)器調(diào)用;從已完成連接隊(duì)列頭返回下一個(gè)已完成連接;如果該隊(duì)列空,則進(jìn)程進(jìn)入睡眠狀態(tài)。 函數(shù)返回的套接字為已連接套接字,應(yīng)與監(jiān)聽套接字區(qū)分開來 該函數(shù)最多:一個(gè)既可能是新套接字也可能是錯(cuò)誤指示的整數(shù),一個(gè)客戶進(jìn)程的協(xié)議地址(由cliaddr所指),以及該地址的大?。ㄟ@后兩個(gè)參數(shù)是值結(jié)果參數(shù));也就是說,服務(wù)器可以通過參數(shù)cliaddr來得到請(qǐng)求連接并獲得成功的客戶的地址和端口號(hào);基本套接字函數(shù)accept幾點(diǎn)說明:幾點(diǎn)說明: 調(diào)用成功時(shí)返回: 1. cliaddr: 客戶進(jìn)程的協(xié)議地址
14、和地址大小 2. 新套接口描述字(已連接套接口描述字) , 監(jiān)聽套接口描述字 listening socket descriptor一個(gè)給定的服務(wù)器常常是只生成一個(gè)監(jiān)聽套接口, 且一直存在,直到該服務(wù)器關(guān)閉。 已連接套接口描述字connected socket descriptor內(nèi)核為每個(gè)被接受的客戶連接創(chuàng)建了一個(gè)已連接套接口。當(dāng)服務(wù)器完成某客戶的服務(wù)時(shí),關(guān)閉已連接套接口。 1024以下的端口:超級(jí)用戶使用#include int close(int sockfd); 返回:0OK;-1出錯(cuò); close函數(shù)缺省功能是將套接字做上“已關(guān)閉”標(biāo)記,并立即返回到進(jìn)程。這個(gè)套接字不能再為該進(jìn)程所用
15、(即不能再接收和發(fā)送數(shù)據(jù),不能作為函數(shù)read和write的參數(shù))。 正常情況下,close將引發(fā)向TCP的四分節(jié)終止序列,但在終止前將發(fā)送已排隊(duì)的數(shù)據(jù); 如果套接字描述符訪問計(jì)數(shù)在調(diào)用close后大于0(在多個(gè)進(jìn)程共享同一個(gè)套接字的情況下),則不會(huì)引發(fā)TCP終止序列(即不會(huì)發(fā)送FIN分節(jié));基本套接字函數(shù)close#include int shutdown(int sockfd, int howto); 返回:0OK;-1出錯(cuò),并置相應(yīng)的errno的值; 該函數(shù)立即發(fā)送FIN分節(jié)(無論其訪問計(jì)數(shù)是否大于0)。shutdown根據(jù)參數(shù)howto關(guān)閉指定方向的數(shù)據(jù)傳輸; SHUT_RD:關(guān)閉連接
16、的讀這一半,不再接收套接字中的數(shù)據(jù)且現(xiàn)留在接收緩沖區(qū)的數(shù)據(jù)作廢; SHUT_WR :關(guān)閉連接的寫這一半(半關(guān)閉),當(dāng)留在套接字發(fā)送緩沖區(qū)中的數(shù)據(jù)都被發(fā)送,后跟tcp連接終止序列,不管訪問計(jì)數(shù)是否大于0;此后將不能在執(zhí)行對(duì)套接字的任何寫操作; SHUT_RDWR:連接的讀、寫都關(guān)閉,這等效于調(diào)用shutdown兩次,一次調(diào)用是用SHUT_RD,第二次用SHUT_WR。基本套接字函數(shù)-shutdown數(shù)據(jù)數(shù)據(jù)FIN數(shù)據(jù)和FIN的確認(rèn)數(shù)據(jù)數(shù)據(jù)FIN數(shù)據(jù)和FIN的確認(rèn)writewriteshutdownRead返回大于0Read返回大于0Read返回0writewritecloseRead返回大于0R
17、ead返回0Read返回大于0客戶服務(wù)器調(diào)用shutdown關(guān)閉一半TCP連接#include int write(int fd, char *buf, int len); 返回:大于0讀寫字節(jié)大小;-1出錯(cuò); 調(diào)用函數(shù)write,有如下幾種情況: 套接字發(fā)送緩沖區(qū)有足夠空間,返回發(fā)送的字節(jié)數(shù); tcp協(xié)議接收到RST數(shù)據(jù),返回1,同時(shí)errno為ECONNRESET; ; 進(jìn)程阻塞過程中接收到信號(hào),返回1,同時(shí)errno為EINTR。write(connfd,buff,strlen(buff);基本套接字函數(shù)write#include int read(int fd, char *buf,
18、int len);返回:大于0讀寫字節(jié)大??;-1出錯(cuò);調(diào)用函數(shù)read時(shí),有如下幾種情況:套接字接收緩沖區(qū)接收數(shù)據(jù),返回接收到的字節(jié)數(shù);tcp協(xié)議收到FIN數(shù)據(jù),返回0;tcp協(xié)議收到RST數(shù)據(jù),返回1,同時(shí)errno為ECONNRESET;進(jìn)程阻塞過程中接收到信號(hào),返回1,同時(shí)errno為EINTR。read(connfd,buff,strlen(buff);基本套接字函數(shù)read#include #include ssize_t send (int fd, const void *msg, size_t len, int flags); 返回:非0發(fā)送成功的數(shù)據(jù)長(zhǎng)度;-1出錯(cuò); flags
19、 是傳輸控制標(biāo)志,其值定義如下: 0:常規(guī)操作,如同write()函數(shù) MSG_OOB,發(fā)送帶外數(shù)據(jù)(TCP緊急數(shù)據(jù))。 MSG_DONTROUTE:忽略底層協(xié)議的路由設(shè)置,只能將數(shù)據(jù)發(fā)送給與發(fā)送機(jī)處在同一個(gè)網(wǎng)絡(luò)中的機(jī)器上。 MSG_DONTWAIT:打開非阻塞模式(了解就OK),執(zhí)行I/O操作,再關(guān)閉非阻塞模式。數(shù)據(jù)傳輸函數(shù)send#include #include ssize_t recv(int fd, void *buf ,size_t len, int flags); 返回:大于0表示成功接收的數(shù)據(jù)長(zhǎng)度;0: 對(duì)方已關(guān)閉,-1:出錯(cuò)。 flags是傳輸控制標(biāo)志,其值定義如下: 0:常
20、規(guī)操作,如同read()函數(shù); MSG_PEEK:只查看數(shù)據(jù)而不讀出數(shù)據(jù),后續(xù)讀操作仍然能讀出所查看的該數(shù)據(jù); MSG_OOB:忽略常規(guī)數(shù)據(jù),而只讀帶外數(shù)據(jù); MSG_WAITALL:recv函數(shù)只有在將接收緩沖區(qū)填滿(也就是len的值)后才返回。 MSG_DONTWAIT:將單個(gè)I/O操作設(shè)為非阻塞模式,執(zhí)行I/O操作,然后關(guān)閉非阻塞標(biāo)志。數(shù)據(jù)傳輸函數(shù)recv 功能:派生新進(jìn)程 create new process 定義:#include pid_t fork (void); 在子進(jìn)程中返回0,在父進(jìn)程中返回子進(jìn)程的進(jìn)程ID 出錯(cuò)時(shí)返回 1,調(diào)用一次返回兩次fork 函數(shù) fork的典型應(yīng)用
21、(多線程): 1一個(gè)進(jìn)程可為自己創(chuàng)建一個(gè)拷貝。當(dāng)一個(gè)拷貝處理一個(gè)操作時(shí),其他的拷貝可以執(zhí)行其他的任務(wù)。這是非常典型的網(wǎng)絡(luò)服務(wù)器。 2一個(gè)進(jìn)程想執(zhí)行其他的程序,由于創(chuàng)建新進(jìn)程的唯一方法是調(diào)用fork,進(jìn)程首先調(diào)用fork來生成一個(gè)拷貝,然后其中一個(gè)拷貝(通常為子進(jìn)程)調(diào)用exec 來代替自己去執(zhí)行新程序。 socket() -得到文件描述符! bind() -我們?cè)谀膫€(gè)端口? connect() -Hello! listen() -有人給我打電話嗎? accept() -Thank you for calling port 3490. send() 和 recv() -Talk to me, b
22、aby! sendto() 和 recvfrom() -Talk to me, DGRAM-style close() 和 shutdown() -滾開! getpeername() -你是誰? gethostname() -我是誰? DNS -你說“白宮”,我說 198.137.240.100簡(jiǎn)而言之簡(jiǎn)而言之實(shí)現(xiàn)TCP套接字基本步驟分為服務(wù)器端和客戶端兩部分:服務(wù)器端 創(chuàng)建套接字; 綁定套接字; 設(shè)置套接字為監(jiān)聽模式,進(jìn)入被動(dòng)接受連接狀態(tài); 接受請(qǐng)求,建立連接 讀寫數(shù)據(jù)終止連接TCP套接字編程客戶端步驟 創(chuàng)建套接字 與遠(yuǎn)程服務(wù)器建立連接 讀/寫數(shù)據(jù);終止連接TCP套接字編程(cont.)in
23、t main(void)int sockfd,connect_sock;if(sockfd=socket(AF_INET,SOCK_STREAM,0)=-1) perror(“create socket failed.”);exit(-1);/* bind sockfd to some address */* listen */loop if(connect_sock=accept(sockfd,NULL,NULL)=-1) perror(“Accept error.”); exit(-1); /* read and process request */close(connect_sock);
24、 close(sockfd);TCP服務(wù)器模板/* include some header files */int main(void)int sockfd;if(sockfd=socket(AF_INET,SOCK_STREAM,0)=-1)perror(“Create socket failed.”);exit(-1);/* connect to server */* send requst and receive response */close(sockfd);TCP客戶模板 采用客戶/服務(wù)器模式,完成下列功能: 客戶根據(jù)用戶提供的IP地址,連接相應(yīng)的服務(wù)器; 服務(wù)器等待客戶的連接,一旦連接成功,則顯示客戶的IP地址,并發(fā)歡迎信息給客戶; 客戶接收服務(wù)器發(fā)送的信息并顯示;TCP套接字例程 下面我們考慮在以下三種異常情況發(fā)生后,tcp客戶服務(wù)器程序的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 道路硬化工程施工方案
- 氣體配送轉(zhuǎn)讓合同范例
- 商洛學(xué)院《中國法律思想史》2023-2024學(xué)年第一學(xué)期期末試卷
- 婚禮搭建合同范例
- 2024年電力設(shè)備租賃與發(fā)電場(chǎng)地使用合同范本3篇
- 汕頭大學(xué)《機(jī)械基礎(chǔ)軸系結(jié)構(gòu)設(shè)計(jì)》2023-2024學(xué)年第一學(xué)期期末試卷
- 汕頭職業(yè)技術(shù)學(xué)院《日本歷史與文化》2023-2024學(xué)年第一學(xué)期期末試卷
- 2024至2030年片狀鋁箔項(xiàng)目投資價(jià)值分析報(bào)告
- 2024至2030年固定提升加料機(jī)項(xiàng)目投資價(jià)值分析報(bào)告
- 預(yù)付款采購合同范例
- GB/T 45008-2024稀土熱障涂層材料鋯酸釓鐿粉末
- 經(jīng)理與領(lǐng)導(dǎo)人員管理制度
- 大國三農(nóng)II-農(nóng)業(yè)科技版智慧樹知到期末考試答案章節(jié)答案2024年中國農(nóng)業(yè)大學(xué)
- 2024年湛江市農(nóng)業(yè)發(fā)展集團(tuán)有限公司招聘筆試沖刺題(帶答案解析)
- (正式版)HGT 6313-2024 化工園區(qū)智慧化評(píng)價(jià)導(dǎo)則
- MOOC 創(chuàng)新思維與創(chuàng)業(yè)實(shí)驗(yàn)-東南大學(xué) 中國大學(xué)慕課答案
- JBT 1472-2023 泵用機(jī)械密封 (正式版)
- 二級(jí)公立醫(yī)院績(jī)效考核三級(jí)手術(shù)目錄(2020版)
- 6人小品《沒有學(xué)習(xí)的人不傷心》臺(tái)詞完整版
- 讀《讓兒童在問題中學(xué)數(shù)學(xué)》有感范文三篇
- 陳述句改成雙重否定句(課堂PPT)
評(píng)論
0/150
提交評(píng)論