我已经创建了一个示例TCP连接函数。这使用带有超时的非阻塞套接字。代码在我们的实验室中正常工作,但在某些网络中,TCP连接失败并出现错误
115这意味着EINPROGRESS。调试发现getsockopt()
后,将iValopt设置为113
我们检查optvalue
是否等于零,如果不是则返回失败。
OS:LINUX Suse10
我的问题是:
getsockopt()
Opt值设置为113而errno设置为115?我也在下面注意到。
你能解释一下原因吗?
我在这里粘贴的确切代码
int tcp_sockconnect_linux(int iSocket, const struct sockaddr* pstSockAddr, unsigned int uiSockAddrLen, unsigned int uiConnectionTimeout)
{
int iRet = 0;
//int iValopt = 0;
int iLength = 0;
struct timeval stTv;
fd_set write_fds;
(void)fcntl((int)(long)iSocket, F_SETFL, O_NONBLOCK);
iRet = connect((int)(long)iSocket, (struct sockaddr*) pstSockAddr, uiSockAddrLen);
if (iRet < 0)
{
if (errno == EINPROGRESS)
{
stTv.tv_sec = uiConnectionTimeout;
stTv.tv_usec = 0;
FD_ZERO(&write_fds);
FD_SET((int)(long)iSocket, &write_fds);
if (0 < select(((int)(long)(iSocket)) + 1,NULL, &write_fds, NULL, &stTv))
{
iLength = sizeof(int);
if (0 > getsockopt((int)(long)iSocket, SOL_SOCKET,SO_ERROR, (void*)(&iValopt), &iLength))
{
return -1;
}
if (0 != iValopt)
{
return -1;
}
return 2;
}
else
{
return -1;
}
}
else
{
return -1;
}
}
return 2;
}
int create_socket(void)
{
int iRet, sock_sd;
struct sockaddr_in saServer;
struct sockaddr_in saLocal;
#ifdef WIN32
WSADATA wsaData;
if(WSAStartup(0x101, &wsaData))
{
printf("Unable to initialize WinSock library.\n");
}
#endif
memset (&saLocal,'\0', sizeof(saLocal));
saLocal.sin_family = AF_INET;
saLocal.sin_addr.s_addr = inet_addr(strBindAddr);
saLocal.sin_port = htons(0);
sock_sd = socket(AF_INET,SOCK_STREAM,0);
memset (&saServer,'\0', sizeof(saServer));
saServer.sin_family = AF_INET;
saServer.sin_addr.s_addr = inet_addr (strServerIP);
saServer.sin_port = htons(uiServerPort);
iRet = bind((unsigned int)sock_sd,(struct sockaddr*) &saLocal,sizeof(saLocal));
#ifdef WIN32
if (iRet == SOCKET_ERROR)
{
printf("\nTCP Bind Failed to LocalIP %s\n",strBindAddr);
}
#else
if (-1 == iRet)
{
printf("\nTCP Bind Failed to LocalIP %s\n",strBindAddr);
}
#endif
#ifdef WIN32
iRet = tcp_sockconnect_win(sock_sd, (struct sockaddr*) &saServer,sizeof(saServer),uiConnectionTimeOut);
if (iRet == SOCKET_ERROR)
{
printf("\nTCP Socket Connect Failed with ErrorNo = %d iValopt = %d LineNo = %d \n",WSAGetLastError(),iValopt,iLineNo);
}
else if (2 == iRet)
{
printf("\nTCP Socket Connect Success \n");
}
#else
iRet = tcp_sockconnect_linux(sock_sd, (struct sockaddr*) &saServer,sizeof(saServer),uiConnectionTimeOut);
if(-1 == iRet)
{
printf("\nTCP Socket Connect Failed with ErrorNo = %d iValopt = %d LineNo = %d\n",errno,iValopt,iLineNo);
}
else if (2 == iRet)
{
printf("\nTCP Socket Connect Success %d\n",iLineNo);
}
#endif
#ifdef WIN32
closesocket (sock_sd);
#else
close(sock_sd);
#endif
return 0;
}
int main ()
{
int iRet = 0;
printf ("Enter the Bind Address (Local IP): ");
scanf("%s" ,&strBindAddr);
printf ("\nEnter the IP Address of Server : ");
scanf("%s" ,&strServerIP);
printf ("\nEnter the PORT Number of Server : ");
scanf("%d" ,&uiServerPort);
printf ("\nEnter the Connection timeout in Seconds : ");
scanf("%d", &uiConnectionTimeOut);
iRet = create_socket();
return 0;
}
答案 0 :(得分:0)
几天前,即使我面临同样的问题。以下是我可以解决的问题。
在WR Stevens的书中,UNIX®网络编程第1卷,第3版:套接字网络API - 16.4非阻塞连接:白天客户端,它讨论了各种连接的不兼容性,我们可以得到一些答案:
正如我们之前所说,各种套接字实现和非阻塞连接存在可移植性问题。首先,在调用select之前,可以完成连接并使数据从对等体到达。在这种情况下,套接字在成功时将是可读写的,就像连接失败一样。我们在图16.11中的代码通过调用
getsockopt
并检查套接字的挂起错误来处理这种情况。接下来是确定连接是否成功完成,如果我们不能假设可写性是返回成功的唯一方法。已经向Usenet发布了各种解决方案。这些将取代我们对图16.11中
getsockopt
的调用。
致电
getpeername
而非getsockopt
。如果此操作因ENOTCONN
而失败,则连接失败,然后我们必须使用getsockopt
调用SO_ERROR
以获取套接字的待处理错误。调用
read
的长度为0.如果read
失败,则connect
失败,errno
read
表示原因连接失败。连接成功后,read
应返回0.- 醇>
再次致电
connect
。它应该失败,如果error
是EISCONN
,则套接字已经连接并且第一个连接成功。
我使用getpeername
尝试了第一个,然后仅在getpeername
失败并显示ENOTCONN
时才会获取错误,并且它对我有效,如下所示:
if(getpeername(ivSocketId, &addr, &addrlen) < 0)
{
if (errno == ENOTCONN)
{
int sockErr = 0;
socklen_t sockErrLen = sizeof(sockErr);
if(getsockopt(ivSocketId, SOL_SOCKET, SO_ERROR,
&sockErr, &sockErrLen) < 0)
{
// Handle errors, may be throw some exceptions
}
if(sockErr == 0)
{
//Handle Success scenario..
return;
}
else
{
// Handle errors, may be throw some exceptions
}
}
else
{
// Handle errors, may be throw some exceptions
}
}