我做了一个简单的socket程序(服务器/客户端)。
服务器在windows上工作,客户端是android应用程序,其中包含由c socket构成的共享库。
在客户端,为了避免冻结,我将套接字更改为非块,而不是在传递connect()函数后回滚到块套接字。之后,我可以使用getpeername()搜索连接。
如下所示。。。

flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags|O_NONBLOCK);

nRet = connect(sock, (struct sockaddr*)&addr, sizeof(addr));
if (nRet < 0)
    if (errno != EINPROGRESS && errno != EWOULDBLOCK)
        return ERR_CONN;

...
...

nRet = select(sock+1, &readset, &writeset, NULL, &tv);
if (nRet == 0)
    if (errno != EINPROGRESS && errno != EWOULDBLOCK)
        return ERR_SELECT;

nRet = getpeername(sock, (struct sockaddr*)&addr, &len);
if (nRet != 0)
    return ERR_GETPEER;

fcntl(sock, F_SETFL, flags);

一切正常。除了在3G模式下工作。
有时,即使服务器已连接,客户端也会在getpeername()中返回错误。
错误代码是ENOTCONN。
我应该采取什么措施来避免这种情况?任何建议都将不胜感激。
提前付款。
我发现了问题所在。
首先,我应该在传递connect()之后而不是在返回之前回滚到块套接字。
其次,select()似乎不能保证为timeval保留,所以我制作了GetTickCount()这样的函数,而不是计数时间来中断循环。
这是我的解决办法。
fcntl(O_NONBLOCK);
connect();
fcntl(BLOCK);

while (true)
{
    fd_set rdfs, wdfs;
    FD_ZERO(&rdfs); FD_ZERO(&wdfs);
    FD_SET(sock, &rdfs); FD_SET(sock, &wdfs);

    tv.tv_sec = 0; tv.tv_usec = 100;
    nRet = select(sock + 1, &rdfs, &wdfs, NULL, &tv);
    if (nRet == -1) return -1;
    else if (nRet)
    {
        nRet = getpeername();
        if (!nRet)
            break;
    }

    if (get_tick_count() - delay > timeout)
        return -2;
}

谢谢!萨诺德,咖啡馆:)

最佳答案

要确定套接字是否已连接,通常使用getsockopt()而不是getpeername()

int so_error;
socklen_t len = sizeof so_error;

getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len);

if (so_error == 0) {
    /* socket is connected */
}

09-25 17:43