我的MFC套接字代码中的CAsyncSocket断言问题和"不正确的参数"错误背后的原因是什么?

Tim*_*Tim 5 c++ sockets mfc casyncsocket

我被要求为朋友查看一些代码.(由于MFC和许多糟糕的代码,我正确地犹豫了,但他赢了......)

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

问题表现在一些不间断的debugbreaks和其他类似的事情 - MFC ENSURE()宏也有问题- 检查套接字是否为null.所有问题都发生在MFC的深处.

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

基于我几个小时的调试,代码非常差,但基本上它正在执行以下操作:

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

  • 调用Connect(服务器,套接字)(在派生CAsyncSocket对象上)
  • OnConnect()我们被通知连接不起作用/没有连接.
  • 在主对话框/应用程序的窗口计时器内有一个计时器.当调用timer event/handler时,我们检查是否已连接.
  • 如果我们检测到我们没有连接(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);
Run Code Online (Sandbox Code Playgroud)

如果我单步执行,那么我会收到消息框:"遇到不正确的参数"

我想(但我不确定)MFC在我关闭它之后试图回拨套接字.它是在一个回调方法(DoCallback())但我已经调用Close()了套接字.

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

pax*_*blo 6

你的选择真的.如果你认为你有更多的运气与另一个套接字实现,那么这样做.

但是,微软有很多开发人员(我相信其中一些甚至可能是好的开发人员).您可能,只是可能,要考虑该故障不会全部铺设在其末端的可能性.

在我看来,您可以获得的API和产品的帮助量也很大.

也许如果您花时间了解MFC模型,您将获得"AHA"时刻并更好地理解它.我不是Winsock的粉丝 - 我更习惯于UNIX世界,其中同步是要走的路,如果你想要async-type behavor,你只需运行单独的进程/线程.

我怀疑,CAsyncSocket仍然受到MFC是一个单线程模型(就GUI而言)这一事实的困扰,尽管Windows已经有一段时间真正的先发制人线程.[我可能错误的是这个hamstrung评论,因为我直接使用Win32已经有一段时间了].


更新:

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

要使用CAsyncSocket对象,请调用其构造函数,然后调用Create函数以创建基础套接字句柄...并为客户端套接字调用Connect成员函数.

至于为什么,我认为这是一个额外的复杂性,因为Windows需要在事件泵浦环境中执行异步套接字,因为它们无法阻止主GUI线程.

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

这很可能是很久以前在WinSock中做出的一个设计决策(可能是在Windows 3.11中,这是一个限制性更强的环境,可以进行异步操作)并继续进行[虽然这是我的猜想,UNIX套接字API从来没有这个一种异步行为,其中消息被抽取,它总是倾向于使用select()或线程/进程].


进一步更新:

如果您在套接字对象上有挂起操作时关闭和/或删除了套接字对象,则通常会发生该断言(非异常).在你的情况下,我建议你关闭时仍然尝试连接.

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

这不是MFC问题,是你朋友的代码违反了合同.如果进行连接(或任何异步操作),则必须在关闭套接字之前等待成功或失败(或继续进行操作) - 在这种情况下,这意味着等待对OnConnect()函数的调用.

从内存中,您可以create()在创建异步套接字时调用,然后发生其他所有操作以响应到达消息队列的消息(即调用您的OnXXX()函数).像所有Win32 GUI一样,消息应该驱动程序(代码运行以响应消息).这段代码看起来越来越像经典编码,其中程序驱动一切 - 这种方式是疯狂的,因为你将拥有你的程序和异步套接字'线程'争夺控制权.

我有一段时间没有看过它,但是你应该能够得到一个CHATSRVR示例程序,它将告诉你如何做到这一点.