跨平台tcp socket通信C++类(后续)

tcp socket在阻塞模式下,调用connect超时时间很长,所以尝试添加超时时间,先设置非阻塞模式,再调用connect,如果返回0,则连接建立成功。如果返回非0,此时通过给select设置超时时间来测试指定时间内连接是否建立成功,调用select,如果select返回值为0,表示在 select 的超时时间内未能成功建立连接,则认为连接建立失败,相反此时我们可以通过调用 getsockopt 来检测集合中的套接口上是否存在待处理的错误,如果存在错误则认为连接建立失败,否则认为成功,再设置回阻塞模式。但在测试过程中发现windows和linux下表现不一样。

windows下(windows10),设置非阻塞模式后,调用connect后会返回10035的错误(代表windows下无法立即完成一个非阻挡性套接字操作),如果无法是无法建立连接的IP,在到达指定的超时时间后select返回值为0,此时认为连接建立失败。

但linux下(ubuntu18)经过测试发现如果是连接不可达的IP,connect失败很快返回错误码101( 网络不可达),此时可认为连接建立失败。如果是可达的IP,connect会返回错误码115( 代表linux下无法立即完成一个非阻挡性套接字操作),此时调用select,即使是不能正常建立连接的ip,select也不会直接返回0,此时无法判断,继续调用getsockopt,在第四个参数中返回了错误码,此时认为连接建立失败。

先记录着,有修改的再更新,这是续篇,其余代码参考

跨平台tcp socket通信C++类_JaneYu7777777的博客-CSDN博客

bool Connect(const char *ip, unsigned short port, int timeOut)
{
	struct sockaddr_in serverAddr;
	int length = 0;

	m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_sockfd == -1)
	{
		printf("************tcp socket error, ip=%s, port=%d***************\n", ip, port);
		return false;
	}

	serverAddr.sin_family = AF_INET;
	//连接服务器的地址
	serverAddr.sin_addr.s_addr = inet_addr(ip);//ip地址的转换
	serverAddr.sin_port = htons(port);


	int nRet = -1;
	int len = sizeof(int);
	timeval tm;
	fd_set set;
	unsigned long ul = 1;
	int nError = -1;
	bool bRet = false;
//设置为非阻塞模式
#ifdef WIN32
	ioctlsocket(m_sockfd, FIONBIO, &ul);
#else
	ioctl(m_sockfd, FIONBIO, &ul);
#endif
	
	nRet = connect(m_sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	nError = GetError();
	printf("************CTcpClient connect nRet=%d errno=%d************\n", nRet, nError);
	if (nRet == -1)
	{
		if ((nError == 10035) || (nError == 115)) // 10035:代表windows下无法立即完成一个非阻挡性套接字操作,115代表linux下无法立即完成一个非阻挡性套接字操作,其它错误认为已经失败
		{
			tm.tv_sec = timeOut;
			tm.tv_usec = 0;
			FD_ZERO(&set);
			FD_SET(m_sockfd, &set);
			nRet = select(m_sockfd + 1, NULL, &set, NULL, &tm);
			printf("************CTcpClient select nRet=%d errno=%d************\n", nRet, GetError());
			if (nRet > 0)
			{
#ifdef WIN32
				getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, (char *)&nRet, &len);				
#else
				getsockopt(m_sockfd, SOL_SOCKET, SO_ERROR, &nRet, (socklen_t *)&len);
#endif
				printf("************CTcpClient getsockopt nRet=%d errno=%d************\n", nRet, GetError());

				if (nRet == 0)
				{
					bRet = true;
				}
				else
				{
					bRet = false;
				}
			}
			else
			{
				bRet = false;
			}
		}
		else
		{
			bRet = false;
		}
	}
	else
	{
		printf("************CTcpClient connect success************\n");
		bRet = true;
	}

	ul = 0;
	//设置为阻塞模式
#ifdef WIN32
	ioctlsocket(m_sockfd, FIONBIO, &ul);
#else
	ioctl(m_sockfd, FIONBIO, &ul);
#endif
	if (!bRet)
	{
		printf("************CTcpClient error, ip=%s, port=%d************\n", ip, port);
		Close();
		return false;
	}

	printf("************CTcpClient success, ip=%s, port=%d************\n", ip, port);
	return true;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值