




已阅读5页,还剩14页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第五章 CSocket工程的建立第一步,建立一个MFC应用程序:第二步,输入文件名及保存路径后点OK:第三步,在页面上选择对话框模式,然后点击Next:第四步,选择Windows Sockets,然后点击Finish,接着点击OK。注意:在这里我们要建两个这样的MFC应用程序,一个叫Client(即:客户端),一个叫Server(即:服务器端);第六章 socket的创建和配置6.1 socket的创建Socket是网络通信过程中端点的抽象表示。Socket在实现中以句柄的形式被创建,包含了进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。为了创建socket,使用socket函数得到一个socket句柄: socket_handle = socket(protocol_family. Socket_type, protocol);其中:protocol_family指定socket使用的协议,取值PF_INET,表示Internet(TCP/IP)协议族;Socket_type指socket面向连接或者使用数据报;第三个参数表示使用TCP或者UDP协议。当一个socket被创建时,WinSock将为一个内部结构分配内存,在此结构中保存此socket的信息,到此,socket连接使用的协议已经确定。下面我们来看一下怎样在程序中创建socket:首先,在客户端新建一个类继承自CSocket类(本例中将它起名为ClientSock),在服务器端新建两个类继承自CSocket类(本例中将它起名为ClistenSock和CWorkSock),至于为什么要这样定义socket的配置中会讲到,这里就先这样定义;其次,WinSock以DLL的形式提供,在调用任何WinSock API之前,必须调用函数WSAStartup进行初始化,再调用函数WSACleanUp作清理工作。MFC使用函数AfxSocketInit包装了函数WSAStartup,在WinSock应用程序的初始化函数IninInstance中调用AfxSocketInit进行初始化。程序不必调用WSACleanUp。这里注意了,WinSock的初始化,已经在创建工程中的第四步做过了,系统已经自动初始化好了,所以这里我们就不在手动初始化了;最后,就是配置socket。6.2 socket的配置对于面向连接的客户,WinSock自动保存本地IP地址和选择协议端口,但是必须使用connect函数配置远地IP地址和远地协议端口:result = connect(socket_handle, remote_socket_address, address_length)remote_socket_address是一个指向特定socket结构的指针,该地址结构为socket保存了地址族、协议端口、网络主机地址。面向连接的服务器则使用bind指定本地信息,使用listen和accept获取远地信息。使用数据报的客户或者服务器使用bind给socket指定本地信息,在发送或者接收数据时指定远地信息。bind给socket指定一个本地IP地址和协议端口,如下:result = bind( socket_hndle, local_socket_address, address_length)参数类型同connect。函数listen监听bind指定的端口,如果有远地客户请求连接,使用accept接收请求,创建一个新的socket,并保存信息。socket_new = accept(socket_listen, socket_address, address_length)面向连接的socket使用send,recv接收数据;使用数据报的socket使用sendto发送数据,recvfrom接收数据。MFC提供了两个类CAsyncSocket和CSocket来封装WinSock API,这给程序员提供了一个更简单的网络编程接口。CAsyncSocket在较低层次上封装了WinSock API,缺省情况下,使用该类创建的socket是非阻塞的socket,所有操作都会立即返回,如果没有得到结果,返回WSAEWOULDBLOCK,表示是一个阻塞操作。CSocket建立在CAsyncSocket的基础上,是CAsyncSocket的派生类。也就是缺省情况下使用该类创建的socket是非阻塞的socket,但是CSocket的网络I/O是阻塞的,它在完成任务之后才返回。CSocket的阻塞不是建立在“阻塞”socket的基础上,而是在“非阻塞”socket上实现的阻塞操作,在阻塞期间,CSocket实现了本线程的消息循环,因此,虽然是阻塞操作,但是并不影响消息循环,即用户仍然可以和程序交互。6.3 CAsyncSocket CAsyncSocket封装了低层的WinSock API,其成员变量m_hSocket保存其对应的socket句柄。使用CAsyncSocket的方法如下:首先,在堆或者栈中构造一个CAsyncSocket对象,例如:CAsyncSocket sock 或者 CAsyncSocket *pSock = new CAsyncSocket其次,调用Create创建socket,例如:使用缺省参数创建一个面向连接的socket:sock.Create();指定参数创建一个使用数据报文socket,本地端口为30:pSocket.Create(30, SOCK_DGRM);其三,如果是客户程序,使用Connect连接到远地;如果是服务程序,使用Listen监听远地的连接请求。其四,使用成员函数进行网络I/O。最后,销毁CAsyncSocket,析构函数调用Close成员函数关闭socket。下面,分析CAsyncSocket的几个函数,从中可以看到它是如何封装低层的WinSock API,简化有关操作的;还可以看到它是如何实现非阻塞的socket和非阻塞操作。1. socket对象的创建和捆绑 :(1)Create函数BOOL CAsyncSocket:Create(UINT nSocketPort, int nSocketType, long lEvent, LPCTSTR lpszSocketAddress) if (Socket(nSocketType, lEvent) if (Bind(nSocketPort,lpszSocketAddress) return TRUE; int nResult = GetLastError(); Close(); WSASetLastError(nResult); return FALSE; 首先,讨论Create函数,分析socket句柄如何被创建并和CAsyncSocket对象关联。Create的实现如下: 其中:参数1表示本socket的端口,缺省是0,如果要创建数据报的socket,则必须指定一个端口号。参数2表示本socket的类型,缺省是SOCK_STREAM,表示面向连接类型。参数3是屏蔽位,表示希望对本socket监测的事件,缺省是FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE。参数4表示本socket的IP地址字符串,缺省是NULL。Create调用Socket函数创建一个socket,并把它捆绑在this所指对象上,监测指定的网络事件。参数2和3被传递给Socket函数,如果希望创建数据报的socket,不要使用缺省参数,指定参数2是SOCK_DGRM。如果上一步骤成功,则调用bind给新的socket分配端口和IP地址。(2)Socket函数其实现如下: BOOL CAsyncSocket:Socket(int nSocketType, long lEvent, int nProtocolType, int nAddressFormat) ASSERT(m_hSocket = INVALID_SOCKET); m_hSocket = socket(nAddressFormat,nSocketType,nProtocolType); if (m_hSocket != INVALID_SOCKET) CAsyncSocket:AttachHandle(m_hSocket, this, FALSE); return AsyncSelect(lEvent); return FALSE; 其中:参数1表示Socket类型,缺省值是SOCK_STREAM。参数2表示希望监测的网络事件,缺省值同Create,指定了全部事件。参数3表示使用的协议,缺省是0。实际上SOCK_STREAM类型的socket使用TCP协议,SOCK_DGRM的socket则使用UDP协议。参数4表示地址族(地址格式),缺省值是PF_INET(等同于AF_INET)。对于TCP/IP来说,协议族和地址族是同值的。在socket没有被创建之前,成员变量m_hSocket是一个无效的socket句柄。Socket函数把协议族、socket类型、使用的协议等信息传递给WinSock API函数socket,创建一个socket。如果创建成功,则把它捆绑在this所指对象。(3)捆绑(Attatch)捆绑过程类似于其他Windows对象,将在模块线程状态的WinSock映射中添加一对新的映射:this所指对象和新创建的socket对象的映射。另外,如果本模块线程状态的“socket窗口”没有创建,则创建一个,该窗口在异步操作时用来接收WinSock的通知消息,窗口句柄保存到模块线程状态的m_hSocketWindow变量中。函数AsyncSelect将指定该窗口为网络事件消息的接收窗口。函数AttachHandle的实现在此不列举了。(4)指定要监测的网络事件在捆绑完成之后,调用AsyncSelect指定新创建的socket将监测的网络事件。AsyncSelect实现如下: BOOL CAsyncSocket:AsyncSelect(long lEvent) ASSERT(m_hSocket != INVALID_SOCKET); _AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState; ASSERT(pState-m_hSocketWindow != NULL); return WSAAsyncSelect(m_hSocket, pState-m_hSocketWindow, WM_SOCKET_NOTIFY, lEvent) != SOCKET_ERROR; 函数参数lEvent表示希望监视的网络事件。_ afxSockThreadState得到的是当前的模块线程状态,m_ hSocketWindow是本模块在当前线程的“socket窗口”,指定监视m_hSocket的网络事件,如指定事件发生,给窗口m_hSocketWindow发送WM_SOCKET_NOTIFY消息。被指定的网络事件对应的网络I/O将是异步操作,是非阻塞操作。例如:指定FR_READ导致Receive是一个异步操作,如果不能立即读到数据,则返回一个错误WSAEWOULDBLOCK。在数据到达之后,WinSock通知窗口m_hSocketWindow,导致OnReceive被调用。指定FR_WRITE导致Send是一个异步操作,即使数据没有送出也返回一个错误WSAEWOULDBLOCK。在数据可以发送之后,WinSock通知窗口m_hSocketWindow,导致OnSend被调用。指定FR_CONNECT导致Connect是一个异步操作,还没有连接上就返回错误信息WSAEWOULDBLOCK,在连接完成之后,WinSock通知窗口m_hSocketWindow,导致OnConnect被调用。对于其他网络事件,就不一一解释了。所以,使用CAsyncSocket时,如果使用Create缺省创建socket,则所有网络I/O都是异步操作,进行有关网络I/O时则必须覆盖以下的相关函数:OnAccept、OnClose、OnConnect、OnOutOfBandData、OnReceive、OnSend。(5)Bind函数经过上述过程,socket创建完毕,下面,调用Bind函数给m_hSocket指定本地端口和IP地址。Bind的实现如下:BOOL CAsyncSocket:Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress) USES_CONVERSION; /使用WinSock的地址结构构造地址信息 SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr); /得到地址参数的值 LPSTR lpszAscii = T2A(LPTSTR)lpszSocketAddress); /指定是Internet地址类型 sockAddr.sin_family = AF_INET; if (lpszAscii = NULL) /没有指定地址,则自动得到一个本地IP地址 /把32比特的数据从主机字节序转换成网络字节序 sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); else DWORD lResult = inet_addr(lpszAscii); /得到地址 if (lResult = INADDR_NONE) WSASetLastError(WSAEINVAL); return FALSE; sockAddr.sin_addr.s_addr = lResult; /如果端口为0,则WinSock分配一个端口(10245000) /把16比特的数据从主机字节序转换成网络字节序 sockAddr.sin_port = htons(u_short)nSocketPort); /Bind调用WinSock API函数bind return Bind(SOCKADDR*)&sockAddr, sizeof(sockAddr); 其中:函数参数1指定了端口;参数2指定了一个包含本地地址的字符串,缺省是NULL。函数Bind首先使用结构SOCKADDR_IN构造地址信息。该结构的域sin_family表示地址格式(TCP/IP同协议族),赋值为AF_INET(Internet地址格式);域sin_port表示端口,如果参数1为0,则WinSock分配一个端口给它,范围在1024和5000之间;域sin_addr是表示地址信息,它是一个联合体,其中s_addr表示如下形式的字符串,“”。如果参数没有指定地址,则WinSock自动地得到本地IP地址(如果有几个网卡,则使用其中一个的地址)。(6)总结Create的过程首先,调用socket函数创建一个socket;然后把创建的socket对象映射到CAsyncSocket对象(捆绑在一起),指定本socket要通知的网络事件,并创建一个“socket窗口”来接收网络事件消息,最后,指定socket的本地信息。下一步,是使用成员函数Connect连接远地主机,配置socket的远地信息。函数Connect类似于Bind,把指定的远地地址转换成SOCKADDR_IN对象表示的地址信息(包括网络字节序的转换),然后调用WinSock函数Connect连接远地主机,配置socket的远地端口和远地IP地址。2. 异步网络事件的处理 当网络事件发生时,“socket窗口”接收WM_SOCKET_NOTIFY消息,消息处理函数OnSocketNotify被调用。“socket窗口”的定义和消息处理是MFC实现的,这里不作详细的讨论。OnSocketNotify回调CAsyncSocket的成员函数DoCallBack,DoCallBack调用事件处理函数,如OnRead、OnWrite等。摘录DoCallBack的一段代码如下:switch (WSAGETSELECTEVENT(lParam) case FD_READ: DWORD nBytes; /得到可以一次读取的字节数 pSocket-IOCtl(FIONREAD, &nBytes); if (nBytes != 0) pSocket-OnReceive(nErrorCode); break; case FD_WRITE: pSocket-OnSend(nErrorCode); break; case FD_OOB: pSocket-OnOutOfBandData(nErrorCode); break; case FD_ACCEPT: pSocket-OnAccept(nErrorCode); break; case FD_CONNECT: pSocket-OnConnect(nErrorCode); break; case FD_CLOSE: pSocket-OnClose(nErrorCode); break; lParam是WM_SOCKET_NOFITY的消息参数,OnSocketNotify传递给函数DoCallBack,表示通知事件。函数IOCtl是CAsyncSocket的成员函数,用来对socket的I/O进行控制。这里的使用表示本次调用Receive函数至多可以读nBytes个字节。从上面的讨论可以看出,从创建socket到网络I/O,CAsyncSocket直接封装了低层的WinSock API,简化了WinSock编程,实现了一个异步操作的界面。如果希望某个操作是阻塞操作,则在调用Create时不要指定该操作对应的网络事件。例如,希望Connect和Send是阻塞操作,在任务完成之后才返回,则可以使用如下的语句: pSocket-Create(0, SOCK_STREAM, FR_WRITE|FR_OOB|FR_ACCEPT|FR_CLOSE);这样,在Connect和Send时,如果是用户界面线程的话,可能阻塞线程消息循环。所以,最好在工作者线程中使用阻塞操作。3. CSocket 如果希望在用户界面线程中使用阻塞socket,则可以使用CSocket。它在非阻塞socket基础之上实现了阻塞操作,在阻塞期间实现了消息循环。对于CSocket,处理网络事件通知的函数OnAccept、OnClose、OnReceive仍然可以使用,OnConnect、OnSend在CSocket中永远不会被调用,另外OnOutOfBandData在CSocket中不鼓励使用。CSocket对象在调用Connect、Send、Accept、Close、Receive等成员函数后,这些函数在完成任务之后(连接被建立、数据被发送、连接请求被接收、socket被关闭、数据被读取)之后才会返回。因此,Connect和Send不会导致OnConnect和OnSend被调用。如果覆盖虚拟函数OnReceive、OnAccept、OnClose,不主动调用Receive、Accept、Close,则在网络事件到达之后导致对应的虚拟函数被调用,虚拟函数的实现应该调用Receive、Accept、Close来完成操作。下面,就一个函数Receive来考察CSocket如何实现阻塞操作和消息循环的。int CSocket:Receive(void* lpBuf, int nBufLen, int nFlags) /m_pbBlocking是CSocket的成员变量,用来标识当前是否正在进行 /阻塞操作。但不能同时进行两个阻塞操作。 if (m_pbBlocking != NULL) WSASetLastError(WSAEINPROGRESS); return FALSE; /完成数据读取 int nResult; while (nResult = CAsyncSocket:Receive(lpBuf, nBufLen, nFlags)= SOCKET_ERROR) if (GetLastError() = WSAEWOULDBLOCK) /进入消息循环,等待网络事件FD_READ if (!PumpMessages(FD_READ) return SOCKET_ERROR; else return SOCKET_ERROR; return nResult; 其中:参数1指定一个缓冲区保存读取的数据;参数2指定缓冲区的大小;参数3取值MSG_PEEK(数据拷贝到缓冲区,但不从输入队列移走),或者MSG_OOB(处理带外数据),或者MSG_PEEK|MSG_OOB。Receive函数首先判断当前CSocket对象是否正在处理一个阻塞操作,如果是,则返回错误WSAEINPROGRESS;否则,开始数据读取的处理。读取数据时,如果基类CAsyncSocket的Receive读取到了数据,则返回;否则,如果返回一个错误,而且错误号是WSAEWOULDBLOCK,则表示操作阻塞,于是调用PumpMessage进入消息循环等待数据到达(网络事件FD_READ发生)。数据到达之后退出消息循环,再次调用CAsyncSocket的Receive读取数据,直到没有数据可读为止。PumpMessages是CSocket的成员函数,它完成以下工作:(1)设置m_pbBlocking,表示进入阻塞操作。(2)进行消息循环,如果有以下事件发生则退出消息循环:收到指定定时器的定时事件消息WM_TIMER,退出循环,返回TRUE;收到发送给本socket的消息WM_SOCKET_NOTIFY,网络事件FD_CLOSE或者等待的网络事件发生,退出循环,返回TRUE;发送错误或者收到WM_QUIT消息,退出循环,返回FALSE;(3)在消息循环中,把WM_SOCKET_DEAD消息和发送给其他socket的通知消息WM_SOCKET_NOFITY放进模块线程状态的通知消息列表m_listSocketNotifications,在阻塞操作完成之后处理;对其他消息,则把它们送给目的窗口的窗口过程处理。4. CSocketFile MFC还提供了一个网络编程模式,可以充分利用CSocket的特性。该模式的基础是CSocketFile类。使用方法就不在这里多做介绍了,有兴趣的朋友可以私下研究;第七章 简单例程的实现下面我们来看一下具体的实现步骤:7.1 界面客户端的主界面是CClientDlg类:登陆界面CODlg类:服务器的界面CserverDlg类:注:把CclientDlg主框架的属性框调出来把Systems menu钩去掉:7.2 实现步骤1. 服务器端获取远地信息,要用到listen和accept,我们先用listen监听bind指定的端口,看有无连接请求,然后再用accept函数留在接受请求。在这里往我们要做的例程中的对话框中添加一个按钮用来点击启动服务器,在按钮的消息响应中先加入Create创建socket,然后加入listen函数,再在ClistenSock中加一个OnAccept函数(可由系统自动添加)在里面创建一个工作socket,然后用accept接受请求即可:void CServerDlg:OnBuStart() / TODO: Add your control notification handler code herem_LSocket.Create(4000);m_LSocket.Listen();注:因为Create和listen都是用来监听的所以都是ClistenSock的属性。在用之前我们要先在CserverDlg.h中定义一个ClistenSock对象。void ClistenSock:OnAccept(int nErrorCode) / TODO: Add your specialized code here and/or call the base classCWorkSock *tmp = new CWorkSock; Accept(*tmp); /CSocket:OnAccept(nErrorCode);这样服务器端就配置好了,就等着客户端发来数据和接受数据了;2. 客户端运行时在弹出主框架前应该先弹出登陆框,登陆框连接服务器端成功后再弹出主框架,那就是说要在弹出主框架前调用登陆框,那就找到负责主框架显示的函数OnInitDialog加以修改即可;BOOL CClientDlg:OnInitDialog()CDialog:OnInitDialog();/ Add About. menu item to system menu./ IDM_ABOUTBOX must be in the system command range.ASSERT(IDM_ABOUTBOX & 0xFFF0) = IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX AppendMenu(MF_SEPARATOR);pSysMenu-AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);/ Set the icon for this dialog. The framework does this automatically/ when the applications main window is not a dialogSetIcon(m_hIcon, TRUE);/ Set big iconSetIcon(m_hIcon, FALSE);/ Set small icon/ TODO: Add extra initialization hereCODlg dlg(m_client); /冒登陆对话框int nResponse = dlg.DoModal();if (nResponse = IDOK)/ TODO: Place code here to handle when the dialog is/ dismissed with OKelse if (nResponse = IDCANCEL)/ TODO: Place code here to handle when the dialog is/ dismissed with Cancelm_strName = dlg.m_SzName;return TRUE; / return TRUE unless you set the focus to a control因为登陆框和主框架都要与服务器端连接并且只能连接一个服务器,所以只能有一个socket对象m_client,这个socket对象m_client在主框架内定义,然后通过构造传值给CODlg类,dlg.DoModal()是创建一个模态对话框。3. 因为是聊天程序,所以我们要往服务器传递名字,标识,聊天内容等数据,这样除了数组、结构体外,不可能再定义别的类型来一次传递了,这里我们用结构体;现在往连接按钮的消息响应中加入如下代码:void CODlg:OnBuLink() / TODO: Add your control notification handler code hereUpdateData(true);if(m_SzName = )MessageBox(用户名不能为空!, Client, MB_ICONWARNING); /用户名不可以为空return;if(!m_client-Create()m_client-Close();:AfxMessageBox(端口错误);return;if(!m_client-Connect(, 4000)m_client-Close();:AfxMessageBox(服务器连接错误);return;Sleep(1000);char* name = m_SzName.GetBuffer(m_SzName.GetLength();T_NETDATAPACK temp;memset(&temp,0,sizeof(temp);temp.type = 1;strcpy(temp.Name,name);m_client-Send(&temp,sizeof(temp);OnOK();Create和connect前面已经详细介绍过了,这里就不多做解释了,send是传递函数,它将数据传给了服务器端。4. 往服务器的工作socket CworkSock中添加一个函数OnReceive(可系统自动添加)用来接受数据并处理:#include listenSock.h#include ServerDlg.hvoid CWorkSock:OnReceive(int nErrorCode) / TODO: Add your specialized code here and/or call the base classthis-Receive(&m_Mess,sizeof(m_Mess); strcpy(m_Name,m_Mess.Name);OnTalk(); CSocket:OnReceive(nErrorCode);OnTalk()函数是处理数据函数:void CWorkSock:OnTalk()switch(m_Mess.type) case 1:(CServerDlg* )(AfxGetApp()-m_pMainWnd)-AddClient(m_Mess); this-Send(&m_Mess,sizeof(T_NETDATAPACK); break;case 2:for(POSITION pos = (CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_SockList.GetHeadPosition();pos != NULL;)CWorkSock *pSocket = (CWorkSock *)(CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_SockList.GetNext(pos);pSocket-Send(&m_Mess,sizeof(T_NETDATAPACK);break;case 3:for(POSITION pos = (CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_SockList.GetHeadPosition(); pos != NULL;)POSITION pos1 = pos;CWorkSock *pSock = (CWorkSock *)(CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_SockList.GetNext(pos);if (strcmp(pSock-m_Name,m_Mess.Name) = 0)(CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_SockList.RemoveAt(pos1);LVFINDINFO find;find.flags = LVFI_STRING ;find.psz = pSock-m_Name;int index;CServerDlg* pMain = (CServerDlg* )(AfxGetApp()-m_pMainWnd);if(index = (pMain-m_listShow.FindItem(&find, -1) != -1)(CWorkSock *)(CServerDlg* )(AfxGetApp()-m_pMainWnd)-m_listShow.DeleteItem(index);pSock-Close();delete pSock;break;break;void CWorkSock:OnClose(int nErrorCode) / TODO: Add your specialized code here and/or call the base classCSocket:OnClose(nErrorCode);用传过来的标识来判断,是传了名字过来,还是传了聊天内容,或登出记录。 5. 因为连接的数目是不确定的所以我们要用链表记录每次的连接,现在加个链表在程序中:先在OnAcept()函数中添加,记录每次创建的socket:void ClistenSock:OnAccept(int nErrorCode) / TODO: Add your specialized code here and/or call the base classCWorkSock *tmp = new CWorkSock; (CSer
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 股东干股协议
- 2025房屋中介服务合同模板范本
- 产品定制生产协议合同书
- 机关事务管理局财务核算中心招聘面试经典题及答案
- 企业商业保险投保协议
- 2025年甘肃省白银市国家公务员行政职业能力测验模拟题(附答案)
- 2025遗产赠与合同范本
- 非营利机构贷款协议
- 借款协议担保条款
- 业务流程自动化实施指南手册
- 地基基础工程施工方法及基础知识课件
- 金风15兆瓦机组变流部分培训课件
- 2017年9月国家公共英语(三级)笔试真题试卷(题后含答案及解析)
- 膀胱镜检查记录
- 2021年西安陕鼓动力股份有限公司校园招聘笔试试题及答案解析
- 化工装置静设备基本知识
- 电脑节能环保证书
- 江西师范大学研究生院非事业编制聘用人员公开招聘1人(专业学位培养办公室助理)(必考题)模拟卷
- 2021社会保险法知识竞赛试题库及答案
- 罐头食品加工工艺课件
- 《排课高手》用户手册
评论
0/150
提交评论