我做了一个简单的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 */
}