c++ - 我的 MFC 套接字代码中的 CAsyncSocket 断言问题和 "improper argument"错误背后的原因是什么?

标签 c++ sockets mfc casyncsocket

我被要求为 friend 查看一些代码。 (由于 MFC 和很多糟糕的代码,我犹豫是对的,但他赢了……)

这是一个基于对话框的应用程序,使用了 CAsyncSocket

问题表现为一些不间断的调试中断和其他类似的事情——MFC ENSURE() 宏也有问题——检查套接字是否为空。所有问题都发生在 MFC 的深处。

一些谷歌搜索显示如果在 Vista/XP 中使用主题可能会发生资源泄漏,但我认为这不是这里的问题。

根据我几个小时的调试,代码很差,但基本上它在做以下事情:

(建立连接时没有问题-只有没有连接时才会出现这种情况)

  • 调用 Connect(server, socket)(在派生的 CAsyncSocket 对象上)
  • OnConnect() 中,我们收到连接无效/未连接的通知。
  • 在主对话框/应用程序的窗口计时器内有一个计时器。当调用计时器事件/处理程序时,我们检查是否已连接。
  • 如果我们检测到我们没有连接(OnConnect() 不好),那么我们调用 CAsyncSocket::Close(),然后调用 CAsyncSocket::Create()(没有参数)然后调用 CAsyncSocket::Connect(server, port)

请注意,对 Connect() 的初始调用没有对 Create() 的调用。

我的第一个真正的问题:

  • 两者有什么区别,为什么需要 Create()? (如果我删除它,它就不再崩溃,但是当我重新建立连接时我也不会连接)

一般问题:

  • 上面代码的设计究竟有什么问题?
  • 这应该如何运作?

编辑:

我修复了代码,以便所有路径都先调用 Create(),然后调用 Connect()

CAsyncSocket::DoCallBack() 中的断言仍然有问题 - 下面代码的最后一行是断言:

void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
    if (wParam == 0 && lParam == 0)
        return;

    // Has the socket be closed - lookup in dead handle list
    CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, TRUE);

    // If yes ignore message
    if (pSocket != NULL)
        return;

    pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);
    if (pSocket == NULL)
    {
        // Must be in the middle of an Accept call
        pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);
        ENSURE(pSocket != NULL);

如果我逐步执行该操作,则会收到消息框:“遇到不正确的参数”

我认为(但不确定)MFC 正试图在我关闭套接字后回调它。它在回调方法 (DoCallback()) 中,但我已经在套接字上调用了 Close()

所以它看起来确实像 MFC 问题,除非我应该先取消订阅。

最佳答案

真的是你的选择。如果您认为使用另一个套接字实现会更幸运,那就去做吧。

但是,Microsoft 有很多开发人员(我相信其中一些甚至可能是优秀的)。您可能,只是可能,想考虑这样一种可能性,即错误并不全都出在他们的头上。

在我看来,您可以获得的有关他们的 API 和产品的大量帮助也不错。

也许如果您花时间了解 MFC 模型,您会得到那个“顿悟”时刻并更好地理解它。我不是 Winsock 的粉丝 - 我更习惯于 UNIX 世界,其中同步是要走的路,如果你想要异步类型的行为,你只需运行单独的进程/线程。

我怀疑 CAsyncSocket 仍然受到 MFC 是单线程模型(就 GUI 而言)这一事实的阻碍,即使 Windows 已经拥有真正的抢占式线程已经有一段时间了。 [我对那个无能为力的评论可能是错误的,我已经有一段时间没有直接使用 Win32 了]。


更新:

根据您声明自己正在做什么的更新,我相当确定您在创建之前不允许连接。引用 http://msdn.microsoft.com/en-us/library/3d46645f(VS.80).aspx ,

To use a CAsyncSocket object, call its constructor, then call the Create function to create the underlying socket handle ... and for a client socket call the Connect member function.

至于为什么,我认为这增加了额外的复杂性,因为 Windows 需要在事件泵环境中执行异步套接字,因为它们不能阻塞主 GUI 线程。

在 UNIXy 环境中,要么没有事件线程(正常进程),要么网络操作只是手动转移到另一个线程(在 GUI 应用程序中)。

这很可能是很久以前在 WinSock 中做出的设计决定(可能是在 Windows 3.11 中,这是一个对执行异步操作有更多限制的环境)并且一直贯彻 [虽然这是我的推测,UNIX 套接字 API 有从来没有这种消息被泵送的异步行为,它总是倾向于使用 select() 或线程/进程。


进一步更新:

如果您关闭和/或删除了套接字对象,而该套接字对象上有待处理的操作,通常会发生该断言(不是异常)。对于您的情况,我建议它在您关闭它时仍在尝试进行连接。

然后当连接成功或失败时,回调被调用并且它无法在表中找到您的套接字。

这不是 MFC 的问题,是你 friend 的代码违反了约定。如果您执行连接(或任何异步操作),则必须在关闭套接字(或进一步处理它)之前等待成功或失败 - 在这种情况下,这意味着等待调用你的 OnConnect() 函数。

根据内存,您在创建异步套接字时调用了 create(),然后所有其他事情都会响应到达消息队列的消息(即调用您的 OnXXX( ) 函数)。像所有 Win32 GUI 东西一样,消息应该驱动程序(代码运行以响应消息)。这段代码看起来越来越像经典编码,其中程序驱动一切 - 这种方式很疯狂,因为您将让您的程序和异步套接字“线程”争夺控制权。

我已经有一段时间没看过它了,但您应该可以得到一个 CHATSRVR 示例程序,它会告诉您如何操作。

关于c++ - 我的 MFC 套接字代码中的 CAsyncSocket 断言问题和 "improper argument"错误背后的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/800734/

相关文章:

c++ - 在qt creator中集成valgrind

c++ - 第 i 个元素返回 i 的函数数组

c++ - 我怎样才能让这个循环分配给 vector 的一半而不是整个 vector ?

c++ - Qt Windows 部署 : Application does not start

c - TCP sendto 返回长度但服务器没有收到任何东西

c++ - 虚拟 CListCtrl 自动调整大小

c# - 在处理 HTTP 客户端时如何知道何时关闭套接字?

python - 结构 : unpack Requires String Argument of Length 16

c++ - 在 CListCtrl 中点击 Escape 与 Enter 触发 LVN_ENDLABELEDIT

c++ - mfc c++ 计算结果为 9 后返回 1