CSocket 和CAsyncSocket类介绍
一、实现方法
微软的 MFC 把复杂的 WinSock API 函数封装到类里,这使得编写网络应用程序更容易。 CAsyncSocket 类逐个封装了 WinSock API ,为高级网络程序员提供了更加有力而灵活的方法。这个类基于程序员了解网络通讯的假设,目的是为了在 MFC 中使用 WinSock ,程序员有责任处理诸如阻塞、字节顺序和在 Unicode 与 MBCS 间转换字符的任务。为了给程序员提供更方便的接口以自动处理这些任务, MFC 给出了 CSocket 类,这个类是由 CAsyncSocket 类继承下来的,它提供了比 CAsyncSocket 更高层的 WinSock API 接口。 Csocket 类和 CsocketFile 类可以与 Carchive 类一起合作来管理发送和接收的数据,这使管理数据收发更加便利。 CSocket 对象提供阻塞模式,这对于 Carchive 的同步操作是至关重要的。阻塞函数(如 Receive() 、 Send() 、 ReceiveFrom() 、 SendTo() 和 Accept() )直到操作完成后才返回控制权,因此如果需要低层控制和高效率,就使用 CasyncSock 类;如果需要方便,则可使用 Csocket 类。
CSocket 类是由 CAsyncSocket 继承而来的,事实上,在 MFC 中 CAsyncSocket 逐个封装了 WinSock API ,每个 CAsyncSocket 对象代表一个 Windows Socket 对象,使用 CAsyncSocket 类要求程序员对网络编程较为熟悉。相比起来, CSocket 类是 CAsyncSocket 的派生类,继承了它封装的 WinSock API 。
一个 CSocket 对象代表了一个比 CAsyncSocket 对象更高层次的 Windows Socket 的抽象, CSocket 类与 CSocketFile 类和 CArchive 类一起工作来发送和接收数据,因此使用它更加容易使用。 CSocket 对象提供阻塞模式,因为阻塞功能对于 CArchive 的同步操作是至关重要的。在这里有必要对阻塞的概念作一解释:一个 socket 可以处于 " 阻塞模式 " 或 " 非阻塞模式 " ,当一个套接字处于阻塞模式(即同步操作)时,它的阻塞函数直到操作完成才会返回控制权,之所以称为阻塞是因为此套接字的阻塞函数在完成操作返回之前什么也不能做。如果一个 socket 处于非阻塞模式(即异步操作),则会被调用函数立即返回。在 CAsyncSocket 类中可以用 GetLastError 成员函数查询最后的错误,如果错误是 WSAEWOULDBLOCK 则说明有阻塞,而 CSocket 绝不会返回 WSAEWOULDBLOCK ,因为它自己管理阻塞。微软建议尽量使用非阻塞模式,通过网络事件的发生而通知应用程序进行相应的处理。但在 CSocket 类中,为了利用 CArchive 处理通讯中的许多问题和简化编程,它的一些成员函数总是具有阻塞性质的,这是因为 CArchive 类需要同步的操作。
在 Win32 环境下,如果要使用具有阻塞性质的套接字,应该放在独立的工作线程中处理,利用多线程的方法使阻塞不至于干扰其他线程,也不会把 CPU 时间浪费在阻塞上。多线程的方法既可以使程序员享受 CSocket 带来的简化编程的便利,也不会影响用户界面对用户的反应。
CAsyncSocket 类编程模型
在一个 MFC 应用程序中,要想轻松处理多个网络协议,而又不牺牲灵活性时,可以考虑使用 CAsyncSocket 类,它的效率比 CSocket 类要高。 CAsyncSocket 类针对字节流型套接字的编程模型简述如下:
1 、构造一个 CAsyncSocket 对象,并用这个对象的 Create 成员函数产生一个 Socket 句柄。可以按如下两种方法构造:
或在指定端口号产生一个数据报套接字
第一种方法在栈上产生一个 CAsyncSocket 对象,而第二种方法在堆上产生 CAsyncSocket 对象;第一种方法中 Create ()成员函数用缺省参数产生一个字节流套接字,第二种方法中用 Create ()成员函数在指定的端口产生一个数字报套接字。 Create ()函数的原型为:
该函数的参数有:
1 )端口, UINT 类型。注意:如果是服务方,则使用一个众所周知的端口供服务方连接;如果是客户方,典型做法是接受默认参数,使套接字可以自主选择一个可用端口;
2 ) socket 类型,可以是 SOCK-STREAM (默认值,字节流)或 SOCK-DGRAM (数据报);
3 ) socket 的地址,例如 "ftp.gliet.edu.cn" 或 "202.193.64.33" 。
2 、如是客户方程序,用 CAsyncSocket ∷ Connect ()成员函数连接到服务方;如是服务方程序,用 CAsyncSocket ∷ Listen ()成员函数开始监听,一旦收到连接请求,则调用 CAsyncSocket ∷ Accept ()成员函数开始接收。注意: CAsyncSocket ∷ Accept ()成员函数要用一个新的并且是空的 CAsyncSocket 对象作为它的参数,这里所说的 " 空的 " 指的是这个新对象还没有调用 Create ()成员函数。
3 、调用其他的 CAsyncSocket 类的 Receive ()、 ReceiveFrom ()、 Send ()和 SendTo ()等成员函数进行数据通信。
4 、通讯结束后,销毁 CAsyncSocket 对象。如果是在栈上产生的 CAsyncSocket 对象,则对象超出定义的范围时自动被析构;如果是在堆上产生,也就是用了 new 这个操作符,则必须使用 delete 操作符销毁 CAsyncSocket 对象。
CSocket 类编程模型
使用 CSocket 对象涉及 CArchive 和 CSocketFile 类对象。以下介绍的针对字节流型套接字的操作步骤中,只有第 3 步对于客户方和服务方操作是不同的,其他步骤都相同。
1 、构造一个 CSocket 对象。
2 、使用这个对象的 Create ()成员函数产生一个 socket 对象。在客户方程序中,除非需要数据报套接字, Create ()函数一般情况下应该使用默认参数。而对于服务方程序,必须在调用 Create 时指定一个端口。需要注意的是, Carchive 类对象不能与数据报( UDP )套接字一起工作,因此对于数据报套接字, CAsyncSocket 和 CSocket 的使用方法是一样的。
3 、如果是客户方套接字,则调用 CAsyncSocket ∷ Connect ()函数与服务方套接字连接;如果是服务方套接字,则调用 CAsyncSocket ∷ Listen ()开始监听来自客户方的连接请求,收到连接请求后,调用 CAsyncSocket ∷ Accept ()函数接受请求,建立连接。请注意 Accept ()成员函数需要一个新的并且为空的 CSocket 对象作为它的参数,解释同上。
4 、产生一个 CSocketFile 对象,并把它与 CSocket 对象关联起来。
5 、为接收和发送数据各产生一个 CArchive 对象,把它们与 CSocketFile 对象关联起来。切记 CArchive 是不能和数据报套接字一起工作的。
6 、使用 CArchive 对象的 Read ()、 Write ()等函数在客户与服务方传送数据。
7 、通讯完毕后,销毁 CArchive 、 CSocketFile 和 CSocket 对象
微软的 MFC 把复杂的 WinSock API 函数封装到类里,这使得编写网络应用程序更容易。 CAsyncSocket 类逐个封装了 WinSock API ,为高级网络程序员提供了更加有力而灵活的方法。这个类基于程序员了解网络通讯的假设,目的是为了在 MFC 中使用 WinSock ,程序员有责任处理诸如阻塞、字节顺序和在 Unicode 与 MBCS 间转换字符的任务。为了给程序员提供更方便的接口以自动处理这些任务, MFC 给出了 CSocket 类,这个类是由 CAsyncSocket 类继承下来的,它提供了比 CAsyncSocket 更高层的 WinSock API 接口。 Csocket 类和 CsocketFile 类可以与 Carchive 类一起合作来管理发送和接收的数据,这使管理数据收发更加便利。 CSocket 对象提供阻塞模式,这对于 Carchive 的同步操作是至关重要的。阻塞函数(如 Receive() 、 Send() 、 ReceiveFrom() 、 SendTo() 和 Accept() )直到操作完成后才返回控制权,因此如果需要低层控制和高效率,就使用 CasyncSock 类;如果需要方便,则可使用 Csocket 类。
CSocket 类是由 CAsyncSocket 继承而来的,事实上,在 MFC 中 CAsyncSocket 逐个封装了 WinSock API ,每个 CAsyncSocket 对象代表一个 Windows Socket 对象,使用 CAsyncSocket 类要求程序员对网络编程较为熟悉。相比起来, CSocket 类是 CAsyncSocket 的派生类,继承了它封装的 WinSock API 。
一个 CSocket 对象代表了一个比 CAsyncSocket 对象更高层次的 Windows Socket 的抽象, CSocket 类与 CSocketFile 类和 CArchive 类一起工作来发送和接收数据,因此使用它更加容易使用。 CSocket 对象提供阻塞模式,因为阻塞功能对于 CArchive 的同步操作是至关重要的。在这里有必要对阻塞的概念作一解释:一个 socket 可以处于 " 阻塞模式 " 或 " 非阻塞模式 " ,当一个套接字处于阻塞模式(即同步操作)时,它的阻塞函数直到操作完成才会返回控制权,之所以称为阻塞是因为此套接字的阻塞函数在完成操作返回之前什么也不能做。如果一个 socket 处于非阻塞模式(即异步操作),则会被调用函数立即返回。在 CAsyncSocket 类中可以用 GetLastError 成员函数查询最后的错误,如果错误是 WSAEWOULDBLOCK 则说明有阻塞,而 CSocket 绝不会返回 WSAEWOULDBLOCK ,因为它自己管理阻塞。微软建议尽量使用非阻塞模式,通过网络事件的发生而通知应用程序进行相应的处理。但在 CSocket 类中,为了利用 CArchive 处理通讯中的许多问题和简化编程,它的一些成员函数总是具有阻塞性质的,这是因为 CArchive 类需要同步的操作。
在 Win32 环境下,如果要使用具有阻塞性质的套接字,应该放在独立的工作线程中处理,利用多线程的方法使阻塞不至于干扰其他线程,也不会把 CPU 时间浪费在阻塞上。多线程的方法既可以使程序员享受 CSocket 带来的简化编程的便利,也不会影响用户界面对用户的反应。
CAsyncSocket 类编程模型
在一个 MFC 应用程序中,要想轻松处理多个网络协议,而又不牺牲灵活性时,可以考虑使用 CAsyncSocket 类,它的效率比 CSocket 类要高。 CAsyncSocket 类针对字节流型套接字的编程模型简述如下:
1 、构造一个 CAsyncSocket 对象,并用这个对象的 Create 成员函数产生一个 Socket 句柄。可以按如下两种方法构造:
CAsyncSocket sock; //
使用默认参数产生一个字节流套接字
Sock.Create();
或在指定端口号产生一个数据报套接字
CAsyncSocket*pSocket=newCAsyncSocket;
int nPort=27;
pSocket->Create(nPort,SOCK-DGRAM);
第一种方法在栈上产生一个 CAsyncSocket 对象,而第二种方法在堆上产生 CAsyncSocket 对象;第一种方法中 Create ()成员函数用缺省参数产生一个字节流套接字,第二种方法中用 Create ()成员函数在指定的端口产生一个数字报套接字。 Create ()函数的原型为:
BOOL Create( UINT nSocketPort = 0, int nSocketType = SOCK_STREAM,
LPCTSTR lpszSocketAddress = NULL );
该函数的参数有:
1 )端口, UINT 类型。注意:如果是服务方,则使用一个众所周知的端口供服务方连接;如果是客户方,典型做法是接受默认参数,使套接字可以自主选择一个可用端口;
2 ) socket 类型,可以是 SOCK-STREAM (默认值,字节流)或 SOCK-DGRAM (数据报);
3 ) socket 的地址,例如 "ftp.gliet.edu.cn" 或 "202.193.64.33" 。
2 、如是客户方程序,用 CAsyncSocket ∷ Connect ()成员函数连接到服务方;如是服务方程序,用 CAsyncSocket ∷ Listen ()成员函数开始监听,一旦收到连接请求,则调用 CAsyncSocket ∷ Accept ()成员函数开始接收。注意: CAsyncSocket ∷ Accept ()成员函数要用一个新的并且是空的 CAsyncSocket 对象作为它的参数,这里所说的 " 空的 " 指的是这个新对象还没有调用 Create ()成员函数。
3 、调用其他的 CAsyncSocket 类的 Receive ()、 ReceiveFrom ()、 Send ()和 SendTo ()等成员函数进行数据通信。
4 、通讯结束后,销毁 CAsyncSocket 对象。如果是在栈上产生的 CAsyncSocket 对象,则对象超出定义的范围时自动被析构;如果是在堆上产生,也就是用了 new 这个操作符,则必须使用 delete 操作符销毁 CAsyncSocket 对象。
CSocket 类编程模型
使用 CSocket 对象涉及 CArchive 和 CSocketFile 类对象。以下介绍的针对字节流型套接字的操作步骤中,只有第 3 步对于客户方和服务方操作是不同的,其他步骤都相同。
1 、构造一个 CSocket 对象。
2 、使用这个对象的 Create ()成员函数产生一个 socket 对象。在客户方程序中,除非需要数据报套接字, Create ()函数一般情况下应该使用默认参数。而对于服务方程序,必须在调用 Create 时指定一个端口。需要注意的是, Carchive 类对象不能与数据报( UDP )套接字一起工作,因此对于数据报套接字, CAsyncSocket 和 CSocket 的使用方法是一样的。
3 、如果是客户方套接字,则调用 CAsyncSocket ∷ Connect ()函数与服务方套接字连接;如果是服务方套接字,则调用 CAsyncSocket ∷ Listen ()开始监听来自客户方的连接请求,收到连接请求后,调用 CAsyncSocket ∷ Accept ()函数接受请求,建立连接。请注意 Accept ()成员函数需要一个新的并且为空的 CSocket 对象作为它的参数,解释同上。
4 、产生一个 CSocketFile 对象,并把它与 CSocket 对象关联起来。
5 、为接收和发送数据各产生一个 CArchive 对象,把它们与 CSocketFile 对象关联起来。切记 CArchive 是不能和数据报套接字一起工作的。
6 、使用 CArchive 对象的 Read ()、 Write ()等函数在客户与服务方传送数据。
7 、通讯完毕后,销毁 CArchive 、 CSocketFile 和 CSocket 对象
转载于:https://blog.51cto.com/laokaddk/215805