最近在solaris下移植heartbeat模块,遇到了一个问题,就是连接其他节点的crm应用程序,有时出现连接失败的问题。
有时返回return -5,有时return-6
代码如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <net/if.h> //struct ifconf 在这里面声明
#include <netinet/in.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#define CRMPORT 3387
#ifndef SOCKET
#define SOCKET int
#endif
#ifndef SOCKET_ERROR
#define SOCKET_ERROR (-1)
#endif
#ifndef INVALID_SOCKET
#define INVALID_SOCKET 0
#endif
//连接指定ip和端口8003,若连接成功,则返回1,否则返回0
int checkConnectToIp(const char *ipStr)
{
int sockfd;
struct sockaddr_in my_addr;
struct timeval timeval_time_out;
int ul = 1;
memset(&(my_addr), 0, sizeof(my_addr)); /* zero my address struct */
my_addr.sin_family = AF_INET; /* host byte order */
my_addr.sin_port = htons((u_short)CRMPORT);
my_addr.sin_addr.s_addr = inet_addr(ipStr);
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
int i = 0;
fprintf(stdout, "checkConnectToIp: socket error-%d!\n",i);
return(sockfd);
}
//增加设置超时时间,超时时间设置为500ms
//初始化超时时间
memset(&timeval_time_out, 0, sizeof(struct timeval));
timeval_time_out.tv_sec= 0;//l_sec为超时时间,秒
timeval_time_out.tv_usec= 500;//l_usec是毫秒
// 设置超时时间,成功返回0
/*if (0!=setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeval_time_out, sizeof(struct timeval)))
{
if (0 != closesocket(sockfd))
return 0;
}*/
// 设置socket为非阻塞模式
int flag;
flag = fcntl(sockfd,F_GETFL,0);
flag |= O_NONBLOCK;
fcntl(sockfd,F_SETFL,flag);//设置非阻塞
char* errMsg;
if (connect(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_in)) == 0)
{
close(sockfd);
return 1;
}
else
{
perror("socket connect");
if (errno == EINPROGRESS)
{
printf("connect EINPROGRESS\n");
}
fd_set fd_set_write;
int optval=0;
int optlen=sizeof(int);
int selectrt = 0;
FD_ZERO(&fd_set_write);
FD_SET(sockfd, &fd_set_write);
selectrt = select(sockfd + 1, NULL, &fd_set_write, NULL, &timeval_time_out);
printf("selectrt---%d\n",selectrt);
if ( 0 < selectrt)
{
if ( 0!=getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) )
{
FD_CLR(sockfd, &fd_set_write);
close(sockfd);
printf("checkConnectToIp:return -4\n");
return -4;
}
printf("optval:%d\n",optval);
if (0!=optval)
{
FD_CLR(sockfd, &fd_set_write);
close(sockfd);
printf("checkConnectToIp:return -5\n");
return -5;
}
FD_CLR(sockfd, &fd_set_write);
}
else
{
FD_CLR(sockfd, &fd_set_write);
close(sockfd);
printf("checkConnectToIp:return -6\n");
return -6;
}
close(sockfd);
return 1;
}
}
int main()
{
int ret = 0;
ret = checkConnectToIp("10.151.12.122"); //连对方ip
printf("checkConnectToIp ret ------ %d\n",ret);
getchar();
return 0;
}
先说下我的思路:
1、通过对方ip和端口,与对方进行connect连接。
2、如果能connect成功,则直接return 1。
3、否则,调用select机制进行连接,如果select超时,则return -6;如果通过select机制,有描述符发生变化,即select返回值大于0,则通过getsockopt判断其SO_ERROR状态,如果SO_ERROR返回值为0,则return 1,否则 return -5。
我遇到的问题和在老大的批评+指导下的分析解决方法为:
1、弄了一个对方ip作为服务端的程序,结果总是return -5。 于是查看服务端代码,一看不是tcp socket,用的是udp socket,哎,图省事不行呀!!! 经改正,代码select返回值为1,测试程序return 1。
2、于是放到大环境中startHB去跑,结果连对端节点的crm,有时返回-6,有时返回1。老大看了看,想可能是select函数在solaris平台和windows平台的用法不一样,于是到google里搜索“openindiana man select return”,发现返回值说明如下:
If the timeout argument is a null pointer, select() blocks until an event
causes one of the masks to be returned with a valid (non-zero) value.
If the time limit expires before any event occurs that would cause one
of the masks to be set to a non-zero value, select() completes success-
fully and returns 0.
RETURN VALUES
On successful completion, select() and pselect() return the total num-
ber of bits set in the bit masks. Otherwise, -1 is returned and errno
is set to indicate the error.
The FD_CLR(), FD_SET(), and FD_ZERO() macros return no value. The
FD_ISSET() macro returns a non-zero value if the bit for the file
descriptor fd is set in the file descriptor set pointed to by fdset,
and 0 otherwise.
意思就是:(1)在超时时间内,有事件发生的话,返回非0值,返回值为多少位被置位了。(2)超时时间到了,select成功执行并且返回值为0。(3)返回-1表示函数出错。
那说明该程序在select的用法上没有错。
3、进一步分析:由于有时返回-6,说明走的是超时的流程。老大说:超时?那是不是时间设置的不对?下面现将超时时间由原来的500毫秒改成1秒试试;再不行再改成2秒;如果还不可以,说明不是时间量的问题,看看事件设置上是不是有区别,有问题。将程序超时时间500毫秒改成1秒后,经大环境测试可以,反复测试10次以上没问题。
很多时候我在努力并坚持去解决问题,但是效果不理想,关键在于“方法”,各位大虾都很有经验,可不可以告诉我该如何锻炼分析问题的方法?除了亲身经历外,有没有什么书籍或杂志,论坛值得推荐?谢谢各位啦~~~~~~