// 归档对象必须关联到文件对象。
(7)arIn >> dwValue; // 进行数据输入。
adOut << dwValue; // 进行数据输出。输入或输出可以反复进行。 (8)sockRecv.Close();
sockServ.Close(); // 传输完毕,关闭监听和连接套接字对象。 客户端:
(1)CSocket sockClient; // 创建空的客户机端套接字对象。 (2)sockClient.Create( ); // 创建套接字对象的底层套接字。 (3)sockClient.Connect( strAddr, nPort ); // 请求连接到服务器。 (4)CSockFile* file ;
file = new CSockFile( &sockClent); //创建文件对象,并关联到套接字对象。 (5)CArchive* arIn, arOut;
arIn = CArchive(&file, CArchive::load); // 创建用于输入的归档对象, arOut = CArchive( &file, CArchive::store); // 创建用于输出的归档对象。 // 归档对象必须关联到文件对象。
(6)arIn >> dwValue; // 进行数据输入。
adOut << dwValue; // 进行数据输出。输入或输出可以反复进行。 (7)sockClient.Close(); // 传输完毕,关闭套接字对象。
第六章 WinInet编程
1. MFC WinInet所包含的类有哪些,分别代表什么?
答:1. 会话类,为CInternetSession类,代表应用程序的一次Internet会话。
2.连接类,代表了与特定网络服务器的连接,包括具连接共性的CInternetConnection类和它的派生类CFtpConnection类、CHttpConnection类、和CGopherConnection类。
3. 文件类,首先包括CInternetFile类和由它派生的CHttpFile类和CGopherFile类,分别对应FTP文件、HTTP请求和Gopher文件的句柄封装;另外,由CFileFind类派生的用于文件查找的CFtpFileFind类和CGopherFileFind类也应归入文件类的层次。
4.错误或异常类,为CInternetException类,代表以上类的成员函数在执行时发生的错误或异常。
2. MFC WinInet 各种类之间的关系
答:如下图,其中细线箭头从基类指向继承类,表示了类的派生关系;粗线箭头从函数指向它所创建的类对象。
3.使用WinInet类编程的一般步骤是什么?
答:1)创建CInternetSession类对象,创建并初始化Internet会话。
2)利用CInternetSession类的QueryOption或SetOption成员函数,可以查询或设置该类内含的Internet请求选项,这一步是可选。
3)创建连接类对象,建立CInternetSession对象与网络服务器的连接,也就是应用程序与网络服务器的连接。
4)创建文件检索类对象,对服务器进行检索。
5)如果需要使用异步操作模式,可以重载CInternetSession类的OnStatusCallback函数,并启动应用程序使用状态回调机制。重载相关函数,加入自己的代码。
6)如果还想更紧密地控制对于服务器文件的访问,可以进一步创建文件类对象实例,完成文件查找或文件读写操作。
7)创建CInternetException类对象实例,处理错误。 8)关闭各种类,将资源释放给系统。
第七章 WinSock的多线程编程
1.什么是WinSock的阻塞模式、非阻塞模式? 各有何优缺点?缺点如何克服?
答:WinSock的两种I/O模式是:“阻塞”模式(Blocking Mode)或“非阻塞”模式,又称为同步模式或异步模式。
阻塞模式的优点:阻塞套接字的I/O操作工作情况比较确定,无非是调用、等待、返回。大部分情况下,I/O操作都能成功地完成,不过就是花费了等待的时间。因而比较容易使用,容易编程。
阻塞模式的缺点:在应付诸如需要建立多个套接字连接来为多个客户服务的时候,或在数据的收发量不均匀的时候,或在输入输出的时间不确定的时候,却显得性能低下,甚至无能为力。
非阻塞模式的优点:能应付诸如需要建立多个套接字连接来为多个客户服务,可以处理数据的收发量不均匀、输入输出的时间不确定等问题。
非阻塞模式的缺点:用非阻塞套接字,需要编写更多的代码,因为必须恰当地把握调用I/O函数的时机,尽量减少无功而返的调用,还必须详加分析每个Winsock调用中收到的WSAEWOULDBLOCK错误,采取相应的对策,这种I/O操作的随机性使得非阻塞套接字显得难于操作。
解决方法:
对于非阻塞的套接字工作模式,进一步引入五种“套接字I/O模型”,有助于应用程序通过一种异步方式,同时对一个或多个套接字上进行的通信加以管理。
对于阻塞的套接字工作模式,则进一步引入多线程机制。多线程机制可以将阻塞限制在某个线程中,从而不影响其它线程的正常工作。
2.说明用户界面线程和工作线程的概念和特点。
答:用户界面线程:通常用来处理用户输入产生的消息和事件,并独立地响应正在应用程序其它部分执行的线程们产生的消息和事件。用户界面线程包含一个消息处理的循环,以应对各种事件。
工作线程:适用于处理那些不要求用户输入并且比较消耗时间的其他任务。对用户来说,工作线程运行在后台。这就使得工作线程特别适合去等待一个事件的发生。在网络编程中,凡是可能引起系统阻塞的操作,都可以用工作线程来完成。
3.简述创建MFC的工作线程所必需的步骤。 答:(1)编程实现控制函数:
一个工作线程对应一个控制函数,线程执行的任务都应编写在控制函数中,控制函数规定了该线程的执行代码,启动线程实际上就是开始运行它对应的控制函数。该控制函数的唯一入口参数是一个指针,用来取得主进程启动该工作线程时传入的参数。
(2)调用AfxBeginThread()函数创建并启动工作线程:
在进程的主线程或其它线程中调用AfxBeginThread()函数创建新的工作线程,并使新线程开始运行。调用该函数时的两个主要入口参数是控制函数指针、传给控制函数的参数指针。
4.简述创建并启动MFC用户界面线程所必需的步骤。
答:1.从CWinThread类派生出自己的线程类,一般借助ClassWizard来做这项工作。 2.改造这个线程类,包括:
①在~.h文件中声明动态创建; ②在~.cpp文件中宣布使用动态创建; ③重载自己线程类的InitInstance();
④创建新的用户界面窗口、并添加所需的控件;
⑤用ClassWizard添加控件成员变量、响应消息的成员函数。
3.调用AfxBeginThread(RUNTIMECLASS(…))函数创建并启动用户界面线程。
5.如何正常终止线程?如何提前终止线程? 答:正常终止线程:
①工作线程:执行完毕时用return 0;便会退出控制函数;
②用户界面线程:在某个事件处理函数中调用PostQuitMessage(),会发送出WM_QUIT消息,在Run()消息循环中收到该消息便会自动退出消息循环、正常终止进程。
提前终止线程:
从线程内调用AfxEndThread函数,就可以强迫线程终止。
6.掌握MFC支持的多线程的两种网络编程实现方式:
工作线程:掌握创建、使用、终止工作线程的网络编程实现方法
用户界面线程:掌握创建、使用、终止用户界面线程的网络编程实现方法
第八章 WinSock的I/O模型
1、非阻塞套接字的五种“套接字I/O模型”及适用场合
select(选择) -- 最基本的I/O模型,Unix/Linux Berkley Socket、Windows Winsock WSAAsyncSelect(异步选择)-- 窗口消息管理时
WSAEventSelect(事件选择)-- 同时管理一或多个套接字时 Overlapped I/O(重叠式I/O)-- 同时控制几个套接字时 Completion port(完成端口)-- 有大量I/O请求提供服务时
2、select模型的操作步骤
select(选择)模型是Winsock中最常见的I/O模型。它的中心思想是利用select函数,实现对多个套接字I/O的管理。
用select操作一个或多个套接字句柄,一般采用下述步骤: (1)使用FD_ZERO宏,初始化自己感兴趣的每一个fd_set集合。
(2)使用FD_SET宏,将要检查的套接字句柄添加到自己感兴趣的每个fd_set集合中,相当于在指定的fd_set集合中,设置好要检查的I/O活动。
(3)调用select函数,然后等待。select完成返回后,会修改每个fd_set结构,删除那些不存在待决I/O操作的套接字句柄,在各个fd_set集合中返回符合条件的套接字。 (4)根据select的返回值,使用FD_ISSET宏,对每个fd_set集合进行检查,判断一个特定的套接字是否仍在集合中,便可判断出哪些套接字存在着尚未完成(待决)的I/O操作。 (5)知道了每个集合中“待决”的I/O操作之后,对相应的套接字的I/O进行处理,然后返回步骤1,继续进行select处理。
3、WSAAsyncSelect异步I/O模型的编程步骤
应用程序在一个套接字上调用WSAAsyncSelect函数时,该函数的hWnd参数指定了一个
窗口句柄。函数成功调用后,当指定的网络事件发生时,会自动执行该窗口对应的窗口回调例程。并将网络事件通知和Windows消息的相关信息,传递给该例程的入口参数,用户可以在该例程中添加自己的代码,针对不同的网络事件进行处理,从而实现有序的套接字输入和输出。 异步I/O模型的编程步骤:
⑴ 用CreateWindow函数创建一个窗口,并为该窗口提供一个窗口回调例程。
⑵ 创建套接字,并调用WSAAsyncSelect函数,指定关注的套接字、窗口句柄、打算接收的
消息,以及程序感兴趣的套接字事件。成功执行WSAAsyncSelec函数,就打开了窗口的消息通知,并注册了事件。
⑶ WSAAsyncSelec函数执行后,当注册的感兴趣套接字事件之一发生时,指定的窗口会收到
指定的消息,并自动执行该窗口的回调例程,可在其中添加自己的代码,处理相应的事件。
4、WSAEventSelect事件选择模型的编程步骤 ⑴创建事件对象:
针对每一个套接字,首先创建一个事件对象。调用WSACreateEvent() 函数,会返回创建好的事件对象句柄。
⑵关联套接字和事件对象,注册关心的网络事件:
调用WSAEventSelect() 函数将事件对象句柄与某个套接字关联在一起,同时注册感兴趣的网络事件类型。
⑶等待网络事件触发事件对象句柄的工作状态:
调用WSAWaitForMultipleEvents() 函数,等待网络事件触发事件对象句柄的工作状态。返回时,确定是在事件对象数组中的哪一个事件对象(它关联着某个套接字)被触发 。 ⑷检查该套接字上所发生的网络事件类型:
调用WSAEnumNetworkEvents() 函数,检查该套接字上发生了什么类型的网络事件。 ⑸处理网络事件:
在确定了套接字上发生的网络事件类型后,就可以根据不同的情况做出相应的处理。 (6)在所有可用的套接字上,继续等待更多的网络事件。
(7)完成事件对象的处理后,调用WSACloseEvent() 函数,释放事件对象。