资源预览内容
第1页 / 共14页
第2页 / 共14页
第3页 / 共14页
第4页 / 共14页
第5页 / 共14页
第6页 / 共14页
第7页 / 共14页
第8页 / 共14页
第9页 / 共14页
第10页 / 共14页
亲,该文档总共14页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
现在大多数语言都支持客户服务器模式编程,其中VB给我们提供了很好的客户服务器编程方式。下面我们用VB来实现 TCP IP 网络编程。TCP IP 协议是 Internet最重要的协议。 VB提供了 WinSock控件, 用于在 TCP IP的基础上进行网络通信。当两个应用程序使用Socket 进行网络通信时,其中一个必须创建 Socket 服务器侦听,而另一个必须创建Socket 客户去连接服务器。这样两个程序就可以进行通信了。1创建服务器,首先创建一个服务端口号。并开始侦听是否有客户请求连接。建立一窗体,并向其增加一个Winsock 控件(可在工程菜单中的部件项来添加此控件),添加两文本框 Text1,Text2,和一按钮 Command1。Private Sub Form_Load() SockServer.LocalPort = 2000 服务器端口号 , 最好大于 1000 SockServer.Listen 开始侦听End Sub Private Sub Form_Unload(Cancel As Integer) SockServer.Close End Sub Private Sub SockServer_Close() SockServer.Close End Sub Private Sub SockServer_ConnectionRequest(ByVal requestID As Long) SockServer.Close SockServer.Accept requestID 表示客户请求连接的ID 号End Sub 当客户向服务器发送数据到达后, 产生 DataArrival事件, 在事件中接收数据,GetData 方法接收数据。Private Sub SockServer_Data Arrival(ByVal bytesTotal As Long) Dim s As String SockServer.GetData s Text1.Text = s End Sub当我需要向客户发送数据时,只需调用SendData方法。Private Sub Command1_Click() SockServer .SendData Text2.Text End Sub2创建客户。要创建客户连接服务器,首先设置服务器主机名,如IP 地址、域名或计算机名,然后设置服务器端口,最后连接服务器。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 14 页 - - - - - - - - - 建立一窗体,并向其增加一个Winsock 控件(可在工程菜单中的部件项来添加此控件),取名为: SockC1 。添加两文本框 Text1,Text2,和一按钮 Command1。Private Sub Form_Load() SockCl.RemoteHost = 127.0.0.1 表示服务器主机名SockCl.RemotePort = 2000 表示服务器端口名SockCl.Connect 连接到服务器End Sub Private Sub Form_Unload(Cancel As Integer) SockCl.Close End Sub Private Sub SockCl_Close() SockCl.Close End Sub Private Sub SockCl_DataArrival(ByVal bytesTotal As Long) Dim s As String SockCl.GetData s 接收数据到文本框中Text1.Text = s End Sub Private Sub Command1_Click() SockCl.SendData Text2.Text 向服务器发送数据End Sub3进行通信。把这两个窗体分别编译成两个EXE文件,服务器 Server.exe 和客户Client.exe 程序,并把它们分别安装在服务器端和客户端,这样就可以实现两者通信了。VB Socket 编程(Winsock 控件创建 TCP/IP 客户机 / 服务器程序 ) Winsock 控件建立在 TCP 、UDP协议的基础上,完成与远程计算机的通信。即使对TCP/IP 不太熟悉的用户,使用该控件也可以在十几分钟内创建一个简单的客户机 / 服务器程序。下面我们对Winsock 控件的事件、方法、属性按其在程序中出现的顺序分别作详细的介绍,以便更好地理解程序源代码。下面是 Winsock 控件的相关属性,方法和事件。(略去一些暂用不到的 ) *属性- LocalHostName | 本地机器名名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 14 页 - - - - - - - - - LocalIP | 本地机器 IP 地址LocalPort | 本地机器通信程序的端口 (0 端口 65536) RemoteHost | 远程机器名RemotePort | 远程机器的通信程序端口state | 连接的当前状态 (文后有详细说明 ) Protocal | 使用 TCP或 UDP协议( 这里我们选0- sckTCPProtocal ) - *方法- Listen Listen 方法用于服务器程序,等待客户访问。格式: Winsock 对象.listen Connect Connect 方法用于向远程主机发出连接请求格式: Winsock 对象.connect 远程主机 IP, 远程端口 Accept Accept 方法用于接受一个连接请求格式: Winsock 对象.accept Request ID Senddata 此方法用于发送数据格式: Winsock 对象.senddata 数据Getdata 用来取得接收到的数据格式: Winsock 对象.getdata 变量 , 数据类型 , 最大长度 Close 关闭当前连接格式: Winsock 对象.close *事件- Close | 远程机器关闭连接时触发Connect | 连接建立好,可以进行通信时触发( 客户端 ) ConnectRequest | 有请求连接到达时产生 ( 服务器端 ) DataArrival | 有数据到达时触发Error | 发生错误时发生SendProgress | 数据传送进度- 服务器程序的实现过程是:(1)服务器程序必须设置好LocalPort属性,作为侦听端口,该值为一个整数(只要是一个其它 TCP/IP 应用程序没有使用过的值即可)。(2)使用 Listen方法进入侦听状态,等待客户机程序的连接请求。(3)客户机程序发出连接请求,使服务器程序产生ConnectionRequest 事件,该事件得到一个参数 requestID 。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 14 页 - - - - - - - - - (4)服务器程序用 Accept 方法接受客户机程序的requestID请求。这样,服务器程序就可以用 SendData方法发送数据了。 Accept 方法必须用上一步得到的requestID 作为其参数。(5)当服务器程序接收到数据时,产生DataArrival事件,参数 BytesTotal包含接收到的数据字节数。在该事件中,可以用GetData 方法接收数据。(6)如果接受到 Close 事件,则用 Close 方法关闭 TCP/IP 连接。客户机程序的实现过程是:(1) 客户程序设置 Remotehost 属性,以便指定运行服务器程序的主机名,该字符串可在“控制面板 | 网络| 标识| 计算机名”中查到。(2) 设置 RemotePort 属性, 以便指定服务器程序的侦听端口。(3)使用 Connect 方法,向服务器提出连接请求。(4) 服务器接受客户机程序的请求, 客户机程序产生Connect 事件,就可以用 SendData方法发送数据了。(5)当客户机程序接收到数据时,产生DataArrival事件,参数 BytesTotal包含接收到的数据字节数。在该事件中,可以用GetData 方法接收数据。(6)如果接受到 Close 事件,则用 Close 方法关闭连接。Winsock 控件还有两个重要的属性, 即 Protocol和 State 。Protocol设定使用的协议是TCP还是 UDP :取值 sckTCPProtocol表示 TCP, 取值 sckUDPProtocol 则表示 UDP 。因为Winsock 控件的缺省设置是sckTCPProtocol ,所以程序中并没有使用 Protocol属性。State 属性反映的是当前TCP/IP 的连接状态,取值如表1 所示。表 1 Winsock 控件的 State 属性及其描述常数 值 描述SckClosed 0 缺省值,关闭SckOpen 1 打开SckListening 2 侦听SckConnectionPending 3 连接挂起SckResolvingHost 4 识别主机SckHostResolved 5 已识别主机SckConnecting 6 正在连接SckConnected 7 已连接SckClosing 8 同级人员正在关闭连接SckError 9 错误先在一台计算机上运行服务器程序,此时窗口上只有一个“退出”按钮。再在另一台计算机上运行客户机程序, 在“连接”按钮右边的文本框中输入服务器的主机名后单击“连接”按钮。如果连接成功,则服务器和客户机程序窗口都会出现两个文本框。这时,两端都可以在上面的文本框中输入文字,这些文字会立即在下面的文本框中出现。服务器程序使用的控件如下:(1)Command1:退出按钮;(2)textsend :发送数据文本框;(3)Winsockserver : 服务器 Winsock;(4)textget :接收数据文本框。服务器程序的界面如图所示。服务器程序的源代码如下:Private Sub Command1_Click() 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 14 页 - - - - - - - - - End End Sub Private Sub Form_Load() textsend.Visible = False textget.Visible = False Winsockserver.LocalPort = 1001 Winsockserver.Listen End Sub Private Sub textsend_Change() Winsockserver.SendData textsend.Text End Sub Private Sub Winsockserver_Close() Winsockserver.Close End End Sub Private Sub Winsockserver_ConnectionRequest(ByVal requestID As Long) textsend.Visible = True textget.Visible = True If Winsockserver.State sckClosed Then Winsockserver.Close Winsockserver.Accept requestID End Sub Private Sub Winsockserver_DataArrival(ByVal bytesTotal As Long) Dim tmpstr As String Winsockserver.GetData tmpstr textget.Text = tmpstr End Sub 客户机程序使用的控件如下:(1)Command1:退出按钮;(2)Command2:连接按钮;(3)Winsockclient:客户 Winsock;(4)Text1 :主机名文本框;(5)Textsend :发送数据文本框;(6)Textget :接收数据文本框;客户机程序的源代码如下:Private Sub Command1_Click() End End Sub Private Sub Command2_Click() Winsockclient.Connect End Sub 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 14 页 - - - - - - - - - Private Sub Form_Load() textsend.Visible = False textget.Visible = False Winsockclient.RemotePort = 1001 Winsockclient.RemoteHost = sccdsz End Sub Private Sub Text1_Change() Winsockclient.RemoteHost = Text1.Text End Sub Private Sub textsend_Change() Winsockclient.SendData textsend.Text End Sub Private Sub Winsockclient_Close() Winsockclient.Close End End Sub Private Sub winsockclient_Connect() textsend.Visible = True textget.Visible = True Command2.Visible = False End Sub Private Sub winsockclient_DataArrival(ByVal bytesTotal As Long) Dim tmpstr As String Winsockclient.GetData tmpstr textget.Text = tmpstr End Sub 1 引言随着网络通信的兴起与迅速发展, TCP/IP 协议已成为计算机网络中最主要的传输协议,TCP/IP 传输协议也越来越为人所熟知。目前的Internet 网就是基于 TCP/IP 协议的互联网络。 TCP/IP 除了用于广域外,在局域网中也广泛应用。TCP 是传输控制协议,它提供了一种可靠的、面向会话连接的数据流服务,它可以在一个分组可能发生丢失、破坏、重复、延迟和乱序的不可靠物理网络之上通过确认、流控、复用同步等自动纠错技术提供一种可靠的进程间通信机制,从而充分保证用户数据传送的可靠和有序性。使用TCP 协议通信时, TCP 建立并控制数据发送方与接收方的会话关系,当接收方正确收到数据后,必须向发送方发送确认信息。如果发送方在指定时间内未能收到确认信息,将重发数据包。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 6 页,共 14 页 - - - - - - - - - IP 指分组交换协议,是联网的主机之间定义数据包传送路由的规则,它的基本任务是通过网络传送数据报,各个IP 数据报之间是相互独立的。IP 本身没有连接协议,在交换数据前不会建立会话关系。 IP 收到数据后也不确认, 发送方和接收方都不检测数据传输的正确性。 所以仅有 IP 是不可靠的, 不能确保正确传输数据。 TCP 与 IP 的组合则构成了功能完整的传输协议。在 TCP/IP 网络应用中,多数网络应用程序是使用客户/ 服务器模型方式,客户向服务器发出服务请求,服务器作出应答响应,服务器通常在一个众所周知的地址侦听客户向服务器发出的请求,服务进程这时一直是处于休眠状态,直到有一个客户程序提出连接请求。服务器作出应答,并为客户提供相应的服务。客户/ 服务器模型最重要的特点是非对等相互作用,客户与服务器处于不平等的地位。服务器拥有客户机所不具备的各种软硬件资源和运算处理能力,服务器提供服务,客户请求服务,这种模式适应了网络资源、 运算能力、信息分布不均等现象, 成为 IP 应用的主要模式。Internet中的 WWW 、FTP、Telnet 、E-mail等许多典型应用都是采用客户/服务器模型方式。Visual Basic是 Windows环境下简单、易学、高效的可视化编程语言开发系统,以其所见即所得的可视化界面设计风格和32 位面向对象的程序设计等特点,已广泛地应用于各个领域,是很多计算机软件开发人员采用的开发工具。VB 不但提供了良好的界面设计能力,而且在网络通信方面的功能也很强。采用VB 开发网络通信应用软件十分方便,尤其软件界面设计非常便捷,编程工作量较小,开发周期短。Visual Basic6.0中提供了 Winsock控件,用于支持网络中两台以上计算机之间进行通信。 Winsock控件提供了多样化的属性和方法来实现网络通信。通过设置 Winsock控件属性及调用控件方法就能够实现TCP 或 UDP 方式的网络通信。因此, 使用 Winsock控件编写网络通信程序的过程,实际上就是设置Winsock控件属性和调用控件方法的过程。利用这个控件,编程人员可以轻松地编写出TCP/IP 客户服务器程序。2 Winsock控件Winsock控件是不可视控件,它提供了访问 TCP 和 UDP 网络服务非常简便的途径,使编程人员开发客户 / 服务器应用程序时,不必了解TCP 的细节或调用低级的WinsockAPIs函数,只通过设置 Winsock控件的属性并调用其方法, 就可直接连接到一台远程计算机进行,并可实现双向数据交换。Microsoft Access、Visual Baisc、Visual C+或 Visual FoxPro都可用其编写客户服务器程序。如果访问 TCP 传输控制协议服务功能,则须建立连接并实现主机间点对点通信。如果访问 UDP 数据文报协议功能,则不建立连接,发送数据将以广播方式上网传输。3 TCP/IP客户服务器程序设计方法名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 7 页,共 14 页 - - - - - - - - - 使用 TCP/IP 协议通讯,首先要指定通信方式为TCP 方式,将 Winsock控件的Protocol属性设置为 sckTCPProtocol.然后,按 TCP 通信协议规定,先要申请建立网络连接,然后才能传输数据。3.1 服务器程序开始侦听网络服务器程序窗体中有三个Winsock控件, Name 分别为 sckServer、sckBusy和sckListen. 其中 sckListen是侦听控件; sckBusy是;sckServer连接控件。 侦听控件和连接控件不能是同一个Winsock控件。服务器程序必须首先侦听网络,等待客户的连接申请,才有可能建立网络连接。服务器程序开始侦听网络前,需要为侦听用(sckListen )控件的 LocalPort属性设置通信接口,然后调用Listen方法。服务器程序开始侦听网络的程序代码如下:sckListen.LocalPort=4477 sckListen.Listen 侦听网络3.2 客户程序申请连接当服务器程序已经启动运行并开始侦听网络后,在客户程序申请连接前,需要为客户 Winsock控件的 RemodeHost属性设置远程主机, 为 RemodePort属性设置通信接口,然后再调用Connect方法向服务器程序申请连接。设置远程主机名,可以是计算机名也可是IP 地址。如果是主机计算机名,则需要系统翻译为相应的 IP 地址;如果是主机IP 地址,则直接进行连接。申请连接的程序代码如下:sckClient.Protocol = sckTCPProtocol 设置协议为 TCP 方式IP 地址127.0.0.1代表本机,与本机的实际地址无关sckClient.RemoteHost = 127.0.0.1129.200.0.1 设置远程主机接口号,该值必须与设置远程主机服务器程序的接口号一致sckClient.RemotePort = 4477 sckClient.Connect 申请连接3.3 服务器程序应答连接请求服务器程序启动侦听网络后, 当客户程序执行Connect方法申请连接时, 服务器程序的侦听控件( sckListen )触发 ConnectionRequest事件,并传递连接请求句柄。编程人员需要在该当事件程序中调用连接控件(sckServer) 的 Accept 方法实现连接。服务器程序应答连接的程序代码如下:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 14 页 - - - - - - - - - Private Sub sckListen_ConnectionRequest(ByVal requestID As Long) sckServer.Accept requestID 应答连接请求End Sub 当服务器程序执行Accept 方法建立连接后,客户程序中的接连控件将触发Connect事件通报连接完成,否则触发Error 事件通报连接失败。可以在该事件程序中加入连接后的处理程序。如果要求服务器程序支持多用户连接,则需要创建 Winsock控件数组,在连接时动态生成 Winsock控件与客户程序建立连接。程序代码应修改如下:Private Sub sckListen_ConnectionRequest(ByVal requestID As Long) Dim i As Long If CurNumberMaxNumber Then MaxNumber为最大连接数, CurNumber为当前连接数For i = 1 To CurNumber If sckServer(i).State = 0 Then 判断是否有空闲Winsock控件Exit For End If Next i If i = CurNumber Then CurNumber = CurNumber + 1 i = CurNumber End If Load sckServer(i) 动态加载 Winsock控件sckServer(i).Accept requestID Exit Sub End If sckBusy.Close sckBusy.Accept requestID End Sub 3.4 传送数据当服务器程序和客户程序连接成功后,可以开始传送数据。建立连接后的服务器程序和客户程序都可以发送或接收数据。当一方要发送数据时,调用SendData方法。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 14 页 - - - - - - - - - Dim SendStr As String SendStr = 连接成功! Winsock1.SendData SendStr 传送数据如果一方发送了数据,在连接的另一方控件将产生DataArrival事件,在DataArrival事件处理程序中需要调用GetData方法接收数据。接收数据类型必须与发送数据的类型一致方可正确接收数据。接收数据的程序代码如下:Dim RecStr As String sckClient.GetData RecStr Print RecStr 3.5 关闭连接当应用程序结束数据传送后,必须关闭连接,释放系统资源。当连接的一方关闭连接时,可以调用 Close 方法。关闭连接程序代码如下:sckClient.Close 关闭连接一方执行关闭连接后, 在连接的另一方控件将产生Close 事件。程序需要处理事件,完成关闭连接的最后工作。该事件的处理代码如下:Private Sub sckServer_Close() sckServer(Index).Close 释放接连Unload sckServer(Index) 删除控件End Sub 4 使用 UDP 通信方式程序设计方法UDP 用户报文协议是一个无连接协议,与TCP 协议操作不同, UDP 协议不使用报文确认机制,不对报文排序,不进行流控,因而UDP 报文可能出现丢失、重复、乱序等现象,但由于它的前期工作比TCP 少,计算机不建立连接,因而可以迅速地展开通信,一般用于传输少量不重要的数据和信息。Winsock控件的 UDP 通信方式是一种广播方式,当 UDP 主机发送数据时,网络上所有其它主机都能收到数据,UDP 通信比TCP 方式简单,由于 UDP 不需要连接,所以没有申请连接和关闭连接的过程。UDP 发送者忽略接收者是否实际收到数据,而接收者也忽略发送者是否已发送了数据。这使编写 UDP 通信方式的网络程序非常简单。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 14 页 - - - - - - - - - 4.1 设置服务器程序中Winsock控件的属性在服务器程序中,需要为Winsock控件的 LocalPort属性设置通信接口:sckserver.LocalPort=4477 4.2 客户程序发送数据当 UDP 主机要发送数据时,可调用SendData方法。发送数据程序的代码如下:Dim SendStr As String SendStr = 发送信息! sckClient.SendData SendStr 传送数据vb 映射已知服务器的方法VB 设定/ 取消 网络磁盘使用方法:建立连线 Function AddConnection(ByVal RemoteLocation As String, _ ByVal LocalDriver As String, _ ByVal Passwd As String, _ ByVal UserName As String) As Boolean RemoteLocation : 为网络磁盘原始来源,格式为 RemoteComputerShareDirectory LocalDriver : 对应本机的磁盘代号,如: H: Passwd : 存取网络磁盘的 Password,传 Null 表示不用密码 UserName : 存取网络磁盘的使用者代号成功时传回 True,否则为 False 例: Call AddConnection(Shihcmias, x:, vbNullString, cww) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 11 页,共 14 页 - - - - - - - - - 取消连线 Function CancelConnection(ByVal LocalDriver As String, _ ByVal ForceClose As Boolean) As Boolean LocalDriver : 对应本机的磁盘代号,如: H: ForceClose : True表示强迫结束连线,而不管有没有程式正与之连线成功时传回 True,否则为 False 例: Call CancelConnection(x:, True) 以下在.bas Option Explicit Type NETRESOURCE dwScope As Long dwType As Long dwDisplayType As Long dwUsage As Long lpLocalName As String lpRemoteName As String lpComment As String lpProvider As String End Type Declare Function WNetAddConnection2 Lib mpr.dll Alias WNetAddConnection2A (lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserName As String, ByVal dwFlags As Long) As Long Declare Function WNetCancelConnection2 Lib mpr.dll Alias WNetCancelConnection2A (ByVal lpName As String, ByVal dwFlags As Long, ByVal fForce As Long) As Long Declare Function WNetGetLastError Lib mpr.dll Alias WNetGetLastErrorA (lpError As Long, ByVal lpErrorBuf As 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 12 页,共 14 页 - - - - - - - - - String, ByVal nErrorBufSize As Long, ByVal lpNameBuf As String, ByVal nNameBufSize As Long) As Long Public Const RESOURCE_PUBLICNET = &H2 Public Const RESOURCETYPE_ANY = &H0 Public Const RESOURCEDISPLAYTYPE_GENERIC = &H0 Public Const RESOURCEUSAGE_CONNECTABLE = &H1 Public Const CONNECT_UPDATE_PROFILE = &H1 Public Function AddConnection(ByVal RemoteLocation As String, ByVal LocalDriver As String, _ ByVal Passwd As String, ByVal UserName As String) As Boolean Dim ne As NETRESOURCE, i As Long Dim errstr As String, errpriv As String, erno As Long ne.dwDisplayType = RESOURCEDISPLAYTYPE_GENERIC ne.dwScope = RESOURCE_PUBLICNET ne.dwType = RESOURCETYPE_ANY ne.dwUsage = RESOURCEUSAGE_CONNECTABLE ne.lpComment = vbNullString ne.lpLocalName = LocalDriver ne.lpProvider = vbNullString ne.lpRemoteName = RemoteLocation i = WNetAddConnection2(ne, Passwd, UserName, 0) If i = 0 Then AddConnection = True Else AddConnection = False errstr = String(256, 0) errpriv = String(256, 0) i = WNetGetLastError(erno, errstr, 256, errpriv, 256) errstr = Left(errstr, InStr(1, errstr, Chr(0) - 1) MsgBox errstr, vbCritical End If 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 13 页,共 14 页 - - - - - - - - - End Function Public Function CancelConnection(ByVal LocalDriver As String, ByVal ForceClose As Boolean) As Boolean Dim i As Long Dim errstr As String, errpriv As String, erno As Long i = WNetCancelConnection2(LocalDriver, 0, IIf(ForceClose, 1, 0) If i = 0 Then CancelConnection = True Else CancelConnection = False errstr = String(256, 0) errpriv = String(256, 0) i = WNetGetLastError(erno, errstr, 256, errpriv, 256) errstr = Left(errstr, InStr(1, errstr, Chr(0) - 1) MsgBox errstr, vbCritical End If End Function 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 14 页,共 14 页 - - - - - - - - -
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号