冬天的苹果 发表于 2011-3-23 15:11:57

寻求帮忙!ACE_SOCK_Dgram::recv中timeout参数不起作用

斑竹还有大家好,寻求帮助,
ACE_SOCK_Dgram中有一个参数timeout,
ssize_t recv (iovec *io_vec,
                ACE_Addr &addr,
                int flags = 0,
                const ACE_Time_Value *timeout = 0) const;
但是在实际中Windows(UDP client 测试工具)发现,这个参数好像没有起作用,recv直接返回-1,时间差不是设定的2秒,而是0。而我希望能一直监听,直到有UDP收到或2秒超时。

代码如下(编译环境VC):
#include "stdafx.h"
#include <iostream>
#include <string>
#include "ace/SOCK_Dgram.h"
#include "ace/Time_Value.h"
#include "ace/OS_NS_unistd.h"
#include "ace/Init_ACE.h"

int _tmain(int argc, _TCHAR* argv[])
{
        ACE::init();

        // local address to be received
        // set port to 0 and let platfrom assign one port.
        ACE_INET_Addr                _localAddr((u_short)0);

        // remoteAddress to be connected and send
        ACE_INET_Addr                _remoteAddr(10088, "127.0.0.1");

        // remoteAddress when receving the data
        ACE_INET_Addr                _remoteRecvAddr(_remoteAddr);

        // ACE UDP Socket
        ACE_SOCK_Dgram                _local;

        // Timer used for receive data
        ACE_Time_Value*         timer_2Sec = new ACE_Time_Value(2);

        //bind the local port(platform assigned) to be used to send/recv data
        int ret = _local.open(_localAddr);
        if (ret != 0)
        {
                std::cout<<"open port return: "<<WSAGetLastError()<<std::endl;
                ACE::fini();
                return -1;
        }

        std::string dataSend("Hello World!");
        char* dataRecv = new char;

        std::cout<<"Test Start!!"<<std::endl;

        for(int i = 0; i<10; i++)
        {
                int byteSent = _local.send(dataSend.data(), dataSend.length(), _remoteAddr);
                if (byteSent < 0)
                {
                        std::cout<<"send return error"<<std::endl;
                        continue;
                } else if(byteSent == 0)
                {
                        std::cout<<"send return 0"<<std::endl;
                        break;
                }
       
                // recving the data until 2 seconds timeout.
                int begin = clock();
                int byteRecv = _local.recv(dataRecv, 100, _remoteRecvAddr, 0, timer_2Sec);
                int end = clock();
       
                if (byteRecv == 0)
                {
                        std::cout<<"recv return 0"<<std::endl;
                } else if ( byteRecv < 0)
                {
                        std::cout<<"recv return -1 after time: "<< end-begin <<std::endl;
                        continue;
                }

                ACE_OS::sleep(1);
        }

        ret = _local.close();
        if (ret != 0)
        {
                std::cout<<"close socket return: "<< ret <<std::endl;
                ACE::fini();
                return -1;
        }

        std::cout<<"Test end!!"<<std::endl;

        ACE::fini();
        return 0;
}

运行结果:
Test Start!!
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
recv return -1 after time: 0
Test end!!

希望大虾们有时间能看看为什么每有2秒就直接返回-1了。
多谢!

冬天的苹果 发表于 2011-3-23 17:57:17

找到Windows返回值了和原因了。
std::cout<<"recv return -1 after time: "<< end-begin <<" error code: "<<WSAGetLastError()<<std::endl;
结果显示:10054
recv return -1 after time: 0 error code: 10054

核对MSDN:
10054: WSAECONNRESET
The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UPD-datagram socket this whould indicate that a previous send operation result in an ICMP "Port Unreachable" message.

recv前面的send 返回ICMP "port unreachable".Server 端没有打开port.

ACE要是能直接返回什么错误就好了,不用再去查找平台文档。
多谢!

冬天的苹果 发表于 2011-3-23 18:15:20

Sorry, 再次更新
1)ACE也会返回error代码 errno 与win32的 WSAGetLastError() 一致
例如:
std::cout<<"recv return -1 after time: "<< end-begin <<" win error code: "<<WSAGetLastError()<<" ace error code: "<< errno <<std::endl;
返回: 
recv return -1 after time: 0 win error code: 10054 ace error code: 10054

所以当recv返回-1的时候,最好也检查errno的值,如果不是ETIME,最好log一下错误
errno == ETIME(timeout超时)
errno == 10054 (recv前面的send返回ICMP "port unreachable".)

2)UDP socket, recv调用如果返回10054,这个时候如果不调用send(), 还可以再次调用recv(),这个时候recv工作正常,2秒超时候就会返回ETIME。 
没有必要对UDP socket 进行ACE_SOCK_Dgram::close然后再ACE_SOCK_Dgram::open。

以上适用Windows平台
页: [1]
查看完整版本: 寻求帮忙!ACE_SOCK_Dgram::recv中timeout参数不起作用