这两天在研究 Windows Socket 编程,今天总算有了一点突破,把自己做的东西发上来。
CAsyncSocket 类在非常低的级别上封装 Windows Sockets API 。 CAsyncSocket 适合那些对网络通信细节很了解,但希望利用回调的便利通知网络事件的程序员使用。如果想利用 Windows Sockets 方便地处理 MFC 应用程序中的多个网络协议,而又不想放弃灵活性,可以考虑使用 CAsyncSocket 。
本文介绍如何用 CasyncSocket 类进行双机通信应用程序的开发。后面附有源程序。
要使用 CasyncSocket 进行通信,首先我们需要创建一个 SOCKET 。可以使用 CasyncSocket 的 Create() 方法。
构造一个 CAsyncSocket 对象并使用该对象创建基础 SOCKET 句柄。
套接字的创建遵循两阶段构造的 MFC 模式。
例如:
上面的第一个构造函数在堆栈上创建一个
CAsyncSocket 对象,第二个构造函数在堆上创建 CAsyncSocket 。上面的第一个 Create 调用使用默认参数创建流式套接字,第二个 Create 调用创建具有指定端口和地址的数据文报套接字。(任一个 Create 版本都可以和任一种构造方法一起使用。)Create 的参数有:
“ 端口 ” :短整型。
对于服务器套接字,必须指定端口 。对于客户端套接字,通常接受此参数的默认值,该值允许 Windows Sockets 选择端口。
套接字类型: SOCK_STREAM (默认值)或 SOCK_DGRAM 。
套接字 “ 地址 ” ,如 “ftp.microsoft.com” 或 “128.56.22.8” 。
该地址为网络上的网际协议 (IP) 地址。很可能要始终依赖此参数的默认值。
SOCKET 创建完之后就可使使用了。如果是客户端就可以使用 CAsyncSocket::Connect 将此套接字对象连接到服务器套接字。如果是服务器端就可以使用使用 CAsyncSocket::Listen 侦听来自客户端的连接尝试。接收到连接请求时,用 CAsyncSocket::Accept 接受该请求。
注意 Accept 成员函数采用对新的空 CSocket 对象的引用作为它的参数。在调用 Accept 之前,必须构造该对象。如果此套接字对象超出范围,则连接关闭。
销毁 CAsyncSocket 对象。
如果在堆栈上创建了套接字对象,当包含函数超出范围时将调用此对象的析构函数。如果使用 new 运算符在堆上创建 了套接字对象,则您必须负责使用 delete 运算符销毁此对象。
析构函数在销毁对象之前调用对象的 Close 成员函数。
当连接建立的时候,就可以进行通信了。 CasycnSocket 类提供以下需要重载的成员函数。
OnAccept |
当服务器端接收到连接请求的时候回调这个函数 |
OnClose |
当连接关闭的时候,回调 |
OnConnect |
当连接尝试结束的时候,回调 ( 此时不能确保连接建立 ) |
OnOutOfBandData |
Notifies a receiving socket that there is out-of-band data to be read on the socket, usually an urgent message. |
OnReceive |
接收到信息的时候回调 |
OnSend |
当发送信息的时候回调 |
连接建立之后,就可以通过 send() 和 receive() 进行数据的收发 ( 当为 TCP 连接的时候 ) ,通过 Sendto() 和 ReceiveFrom () 收发数据,当为 UDP 连接的时候。
废话少说,放上我的例程,整个程序的主要部份就是自己构造的一个新类 CmySocket() 进行通信。里面传递了当前聊天窗体的句柄句柄,以便使用回调函数调用窗体类进行事件响应。
程序不是很大,有兴趣的朋友可以和我联系。
源程序下载
最后附上通讯的流程。
服务器 |
客户端 |
// 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 arOut(&file, - 或两者 - |
// construct an archive CArchive arIn(&file, - 或 - CArchive arOut(&file, - 或两者 - |
// 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 成员函数。有关顺序的其他说明