Windows Socket && Socket In MFC

  最近工作中要调查一段程序从Windows 2000迁移到Windows Vista环境中,该程序是一个典型的客户端/服务器程序. 客户端为Windows. 服务器为Linux. Linux服务器提供了FTP/Telent服务.
   客户端需要经常到Linux服务器上通过FTP上传和下载文件数据.当客户端运行在win2000/XP环境中时,一切运行良好,但在Vista环境中,则两者之间的通信受阻,而具体原因通过抓包分析,则是Windows Socket API在发送FTP包时,在Vista机器中,数据包发送交是本机的hostname,而非IP地址.
   于是,需要对程序中涉及到Windows Socket 及MFC中的CAsyncSocket的继承类进行分析,并排查.究竟是哪地方出现问题。
   这篇文章,把最近关于在Windows中进行网络编程所涉及的基础知识记录下来. 希望能够近期解决以上问题.
   另,Windows Vista实在实在实在是太BT了........................不断的弹对话框提示框要把人逼疯!

 

套接字的定义

套接字是一个通信终结点,它是 Windows Sockets 应用程序用来在网络上发送或接收数据包的对象。套接字具有类型,与正在运行的进程相关联,并且可以有名称。目前,套接字一般只与使用网际协议组的同一“通信域”中的其他套接字交换数据。

可用的套接字类型有以下两种:

  • 流式套接字

    流式套接字提供没有记录边界的数据流,即字节流。字节流能确保以正确的顺序无重复地被送达。

  • 数据文报套接字

    数据文报套接字支持面向记录的数据流,但不能确保能被送达,也无法确保按照发送顺序或不重复。

SOCKET 数据类型

每一个 MFC 套接字对象封装一个 Windows Sockets 对象的句柄。该句柄的数据类型为 SOCKETSOCKET 句柄类似于窗口的 HWND。MFC 套接字类提供对封装句柄的操作。


套接字编程模型

  • CAsyncSocket

    该类封装 Windows Sockets API。CAsyncSocket 是为那些了解网络编程并希望能够灵活地对套接字 API 直接编程,同时还希望方便地使用回调函数以进行网络事件通知的程序员提供的。除了将套接字打包为面向对象的形式以用于 C++ 外,此类提供的唯一附加抽象化是将某些与套接字相关的 Windows 消息转换为回调。有关更多信息,请参见 Windows Sockets:套接字通知

  • CSocket

    此类由 CAsyncSocket 所派生,它通过 MFC CArchive 对象提供与套接字一起使用的更高级的抽象化。使用带存档的套接字与使用 MFC 的文件序列化协议非常相似。这使它比 CAsyncSocket 模型更易于使用。CSocket 从 CAsyncSocket(它封装 Windows Sockets API)继承了许多成员函数;您将必须使用其中一些函数并一般性地了解套接字编程。而 CSocket 则管理着必须由您自己使用原始 API 或 CAsyncSocket 类来管理的通信的许多方面。最重要的是,CSocket 使用 Windows 消息的后台处理来提供阻塞,这对 CArchive 的同步操作非常关键。


 

Windows Sockets:流式套接字

 流式套接字一般用于TCP协议蔟中,如创建FTP,TELNET应用程序都使用流式套接字,创建流式套接字为SOCK_STREAM.
流套接字适合文件传输协议 (FTP) 这类实现,此协议有利于传输任意大小的 ASCII 或二进制文件。

如果必须保证数据送达而且数据大小很大时,流式套接字优于数据文报套接字。

此例可详见:MFC 示例 CHATTERCHATSRVR

流式套接字通信的操作顺序

在构造 CSocketFile 对象之前,下面的顺序对 CAsyncSocketCSocket 都是准确的(只有少数几个参数不同)。从构造 CSocketFile 对象开始,顺序只适用于 CSocket。下表阐释了在客户端和服务器之间设置通信的操作顺序。

设置服务器和客户端之间的通信

服务器 客户端
// construct a socket

CSocket sockSrvr;

// construct a socket

CSocket sockClient;

// create the SOCKET

sockSrvr.Create(nPort);1,2

// create the SOCKET

sockClient.Create( );2

// start listening

sockSrvr.Listen( );

 
  // seek a connection

sockClient.Connect(strAddr, nPort);3,4

// construct a new, empty socket

CSocket sockRecv;

// accept connection

sockSrvr.Accept( sockRecv ); 5

 
// construct file object

CSocketFile file(&sockRecv);

// construct file object

CSocketFile file(&sockClient);

// construct an archive

CArchive arIn(&file,
         CArchive::load);

- 或 -

CArchive arOut(&file,
         CArchive::store);

- 或两者 -

// construct an archive

CArchive arIn(&file,
         CArchive::load);

- 或 -

CArchive arOut(&file,
         CArchive::store);

- 或两者 -

// use the archive to pass data:

arIn >> dwValue;

- 或 -

arOut << dwValue;6

// use the archive to pass data:

arIn >> dwValue;

- 或 -

arOut << dwValue;6

1. 这里的 nPort 是端口号。有关端口的详细信息,请参见 Windows Sockets:端口和套接字地址

2. 服务器必须始终指定一个端口,以便客户端可以连接。Create 调用有时也指定地址。在客户端使用默认参数,这些参数要求 MFC 使用任何可用端口。

3. 这里的 nPort 是端口号,strAddr 是计算机地址或网际协议 (IP) 地址。

4. 计算机地址可以采用几种形式:“ftp.microsoft.com”、“microsoft.com”。IP 地址采用“以点分隔的数字”形式,如“127.54.67.32”。Connect 函数查看地址是否为以点分隔的数字(但它不确保该数字是网络上的有效计算机)。如果不是,则 Connect 使用其他某种形式的计算机名称。

5. 当在服务器端调用 Accept 时,传递对新套接字对象的引用。必须首先构造该对象,但不对它调用 Create。注意,如果此套接字对象超出范围,则连接关闭。MFC 将新对象连接到 SOCKET 句柄。可以在堆栈上构造此套接字(如表中所示)或在堆上构造。

6. 存档和套接字文件在超出范围时将被关闭。套接字对象超出范围或被删除时,对象的析构函数也对此套接字对象调用 Close 成员函数。

有关顺序的其他说明

上表中显示的调用顺序适用于流式套接字。数据文报套接字是无连接的,不需要 CAsyncSocket::Connect、Listen 和 Accept 调用(但可有选择地使用 Connect)。相反,如果正在使用 CAsyncSocket 类,则数据文报套接字使用 CAsyncSocket::SendToReceiveFrom 成员函数。(如果对数据文报套接字使用 Connect,则使用 SendReceive。)因为 CArchive 不适用于数据文报,如果套接字是数据文报,则不要使用带存档的 CSocket

CSocketFile 并不支持 CFile 的所有功能,CFile 成员(如 Seek)对套接字通信没有意义,是不可用的。因此,某些默认 MFC Serialize 函数与 CSocketFile 不兼容。这对于 CEditView 类更是如此。不要试图使用 CEditView::SerializeRaw 通过附加到 CSocketFile 对象的 CArchive 对象来序列化 CEditView 数据,而应使用 CEditView::Serialize(无出处)。SerializeRaw 函数预期文件对象具有 CSocketFile 不支持的函数,如 Seek

posted @ 2007-05-21 16:10  shipfi  阅读(2096)  评论(0编辑  收藏  举报