那我们如何设计这个类呢?为了通知到使用者,我们必须设计为类似事件通知的方式,也就是相当于.net的委托。
我们新建一个类,叫“CTcpClient”,继承 CAsyncSocket。
然后我们在这个类的上面 声明2个函数指针,用来作为事件的通知。代码如下:
class CTcpClient;
typedef void (*pSocketEvent)(CTcpClient *tcpClient);
typedef void (*pSocketErrorEvent)(CTcpClient *tcpClient,int nErrorCode);
我们先看一个函数指针,为什么要求参数是自身?如果站在服务器的角度来看的话,这个问题就不难解释。设想一下,当所有CTcpClient 的相同事件使用了同一个函数,那么服务器如何区别这个函数到底被哪一个CTcpClient 调用呢?所以,参数的意义就这里。我们继续看第2个函数指针,这个事件是用来通知 Socket发生错误的,第1个参数同上,第2个参数表示错误代码,根据这个错误代码你可以知道发生了什么错误。很不幸的是,要想知道这个错误代码的意思,必须使用VS自带的一个工具来查询,但是如果你在运行的时候,将这个错误代码弹出来反馈给用户,这样显的非常不友好,用户也不知道发生了什么事情,估计就是开发人员是不能直接看出来,那么,为了解决这个问题,我们后面再讲。接下来,我们添加如下代码:
public:
typedef pSocketEvent SocketEventHandle;
typedef pSocketErrorEvent SocketErrorEventHandle;
//成功事件
SocketEventHandleConnectEvent;
//错误事件
SocketErrorEventHandleConnectErrorEvent;
紧接着重写连接的虚函数:
protected:
virtual void OnConnect(int nErrorCode);
virtual voidOnConnect(void);
virtual voidOnCloseError(int nErrorCode);
TcpClient.cpp代码如下:
//构造函数
CTcpClient::CTcpClient(void):
ConnectEvent(NULL),
ConnectErrorEvent(NULL)
{
}
void CTcpClient::OnConnect(intnErrorCode)
{
if(nErrorCode)
this->OnConnectError(nErrorCode);
else
this->OnConnect();
}
void CTcpClient::OnConnect(void)
{
if(ConnectEvent)
ConnectEvent(this);
}
void CTcpClient::OnConnectError(intnErrorCode)
{
if(ConnectErrorEvent)
ConnectErrorEvent(this,nErrorCode);
}
通过以上的代码,我们构建了这样的一个蓝图:如果调用者对我们的事件感兴趣的话,那么他可以选择他感兴趣的事件去注册,正如.net里面的事件一样,不过与.net不同的是,成员函数不能作为回调函数使用,必须置为 static ,这样一来使得你的程序需要添加一个全局指针才能在回调函数访问您的实例成员。(未完待续)