65.9K
CodeProject 正在变化。 阅读更多。
Home

CAsyncSocketEx - CAsyncSocket 的替代品,支持代理和 SSL

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (35投票s)

2003年3月26日

6分钟阅读

viewsIcon

515360

downloadIcon

15682

CAsyncSocketEx 是 CAsyncSocket 的一个无 MFC 替代品,它还提供了一个灵活的层系统。通过层类 CAsyncProxySocketLayer,您可以连接到代理服务器。

引言

CAsyncSocketExCAsyncSocket 的一个无 MFC 替代品,它还提供了一个灵活的层代码。编写此类的原因是 CAsyncSocket 不是最快的 WinSock 包装器,并且很难向 CAsyncSocket 派生类添加新功能。此类支持 CAsyncSocket 的大部分功能,并且可以很容易地扩展。通过层系统,您可以轻松实现透明层,例如代理或 SSL 层。

一个好处是 CAsyncSocketEx 无需 MFC 即可工作,但如果启用了 MFC (定义了 _AFX),CAsyncSocketEx 会提供一些接受 CString 作为参数的函数,因此 CAsyncSocketExCAsyncSocket 兼容。

CAsyncProxySocketLayerCAsyncSocketEx 的一个层类。借助它,您可以通过代理服务器进行连接。该层几乎是透明的,因此您无需修改太多代码即可使用它。其他层也可以很容易地编写,只需从 CAsyncSocketExLayer 派生新的层类即可。

另一个层类是 CAsyncSslSocketLayer,可用于与服务器建立 SSL 连接。

使用代码

要使用 CAsyncSocketEx,只需将代码中所有 CAsyncSocket 的出现替换为 CAsyncSocketEx。如果您没有以任何方式增强 CAsyncSocket 本身,则无需更改代码中的任何其他内容。但是,如果您在代码中使用 IOCtlSetSockOpt,则可能会出现问题,CAsyncSocketEx 和层类不会识别您是否使用 IOCtlSetSockOpt 更改了任何选项。

CAsyncSocketEx 提供了一些有用的新功能

// Triggers an event on the socket
// Any combination of FD_READ, FD_WRITE, FD_CLOSE, 
//FD_ACCEPT, FD_CONNECT and FD_FORCEREAD is valid for lEvent.
BOOL TriggerEvent(long lEvent);

使用 TriggerEvent,您可以明确触发在 OnReceiveOnSend 等中处理的通知消息。

例如,TriggerEvent(FD_SEND); 会向内部 helper 窗口发送一条消息并返回。稍后,如果处理了此消息,则将调用 OnSend

FD_READ 有一些特殊之处:OnReceive 仅在确实有任何数据可用时才会被调用。无论是否有数据等待,要触发对 OnReceive 的调用,请改用 FD_FORCEREAD

其他新功能用于新的层系统。

使用层系统

使用层系统非常简单。在大多数情况下,创建一个层类的新实例并将其附加到 CAsyncSocketEx 实例就足够了。

//Attaches a new layer to the socket.
BOOL AddLayer(CAsyncSocketExLayer *pLayer);

这会向套接字添加一个从 CAsyncSocketExLayer 派生的新层。您可以添加多个层。最后添加到层列表的层直接作用于套接字,其他层作用于前一个层。您对 CAsyncSocketEx 的所有调用都首先由添加到列表的第一个层处理。示例:如果您想通过代理服务器与服务器建立 SSL 连接,首先添加 SSL 层(参见 CAsyncSslSocketLayer 文章),然后添加代理层。

//Resets layer chain.
void RemoveAllLayers()

此函数将所有层从套接字分离。但它不会销毁层类实例,您仍然负责销毁层实例。理论上,可以将先前从套接字分离的层添加到新套接字,但不建议这样做。您应该为每个建立的连接创建并附加层的新实例。

//Called by the layers to notify application of some events
virtual int OnLayerCallback(const CAsyncSocketExLayer *pLayer, 
                            int nType, int nParam1, int nParam2);

此函数由各层调用,用于通知程序有关层的重要事件。第一个参数标识发送通知消息的层。第二个参数是通知的类型。有效的通知类型是

  • LAYERCALLBACK_STATECHANGE

    当层的状态发生变化时发送此通知。nParam1 包含新状态,nParam2 包含旧状态。有效状态是

    • 0 - 无效套接字
    • 1 - 未连接
    • 2 - 正在连接
    • 3 - 正在监听
    • 4 - 已连接
    • 5 - 已关闭
    • 6 - 已中止
  • LAYERCALLBACK_LAYERSPECIFIC

    此通知在每个层特有的事件上发送。有关此通知消息的含义和参数,请参阅层的描述。

CAsyncProxySocketLayer

使用此层,您可以通过代理服务器进行连接。此类支持 SOCKS4/5 以及 HTTP/1.1(使用 CONNECT 方法)代理。有关 SOCKS4/5 的更多信息,请访问 http://www.socks.nec.com/socksprot.html,有关 HTTP 1.1 的更多信息,请访问 http://www.rfc-editor.org/ 并搜索 RFC2616。

要使用 CAsyncProxySocketLayer,您无需更改现有代码中的太多内容。要使用它,请创建 CAsyncProxySocketLayer 的实例,调用 SetProxy 并将其附加到 CAsyncSocketEx 实例。您必须在 CAsyncSocketEx 实例中处理 OnLayerCallback,因为它将接收所有层通知。

发送以下通知(类型为 LAYERCALLBACK_LAYERSPECIFIC

  • 错误代码
    PROXYERROR_NOERROR 0
    PROXYERROR_NOCONN 1 无法连接到代理服务器,请使用 GetLastError 获取更多信息
    PROXYERROR_REQUESTFAILED 2 请求失败,无法发送数据
    PROXYERROR_AUTHREQUIRED 3 需要身份验证
    PROXYERROR_AUTHTYPEUNKNOWN 4 身份验证类型未知或不受支持
    PROXYERROR_AUTHFAILED 5 身份验证失败
    PROXYERROR_AUTHNOLOGON 6
    PROXYERROR_CANTRESOLVEHOST 7
  • 状态消息
    PROXYSTATUS_LISTENSOCKETCREATED 8 成功创建监听套接字时调用。与普通监听函数不同,SOCKS 化套接字必须连接到代理以与将创建监听套接字的服务器协商详细信息。这两个参数将包含服务器上监听套接字的 IP 和端口。

如果您想使用 CAsyncProxySocketLayer 创建监听套接字,则必须使用此重载函数

BOOL PrepareListen(unsigned long serverIp);

serverIP 是您已通过 SOCKS 代理连接到的服务器的 IP。您不能在没有主连接的情况下通过 SOCKS 代理使用监听套接字。监听套接字仅由 SOCKS 代理支持,这不适用于 HTTP 代理。

当监听套接字成功创建时,将发送 PROXYSTATUS_LISTENSOCKETCREATED 通知。参数将告诉您监听套接字的 IP 和端口。之后,您必须处理 OnAccept 消息并接受连接。

调用 Accept 时要小心:rConnected 套接字将不会被填充!而是使用创建监听套接字的实例,它将处理数据连接。

如果您想接受多个连接,则必须为每个连接创建一个监听套接字!

重要函数及其参数的描述

void SetProxy(int nProxyType);
void SetProxy(int nProxyType, CString ProxyHost, int nProxyPort);
void SetProxy(int nProxyType, CString ProxyHost, int nProxyPort,
                            CString ProxyUser, CString ProxyPass);

调用其中一个函数来设置代理类型。

参数

  • nProxyType 指定代理类型。
  • ProxyHostnProxyPort 指定代理的地址
  • ProxyUserProxyPass 仅适用于 SOCKS5 代理。

支持的代理类型

  • PROXYTYPE_NOPROXY
  • PROXYTYPE_SOCKS4
  • PROXYTYPE_SOCKS4A
  • PROXYTYPE_SOCKS5
  • PROXYTYPE_HTTP11

还有一些其他函数

int GetProxyType();

返回使用的代理。

const int GetLastProxyError() const;

返回最后一个代理错误,有关可用错误代码的列表,请参见上文。

已知限制

  • 不支持阻塞模式
  • IOCtl / SetSockOpt 不完全支持,请谨慎使用。
  • 不支持 SOCK_DGRAM (UDP),仅支持 SOCK_STREAM (TCP)。

版本历史

  • 2003-03-29 - 小修复
  • 2003-03-28 - Connect 现在使用 WSAAsyncGetHostByName 解析主机名,不再阻塞整个线程
  • 2003-03-26 - 首次公开发布
© . All rights reserved.