如何锻炼分析问题的方法?请各位大虾指教~~

个人感悟 专栏收录该内容
4 篇文章 0 订阅

最近在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次以上没问题。

很多时候我在努力并坚持去解决问题,但是效果不理想,关键在于“方法”,各位大虾都很有经验,可不可以告诉我该如何锻炼分析问题的方法?除了亲身经历外,有没有什么书籍或杂志,论坛值得推荐?谢谢各位啦~~~~~~

  • 1
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值