客户端长连接断线重连机制

// testsocketclient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

#include <winsock2.h>
#include <stdio.h>
#include <mstcpip.h>
#pragma comment(lib, "Ws2_32.lib")
SOCKET sockClient = 0;
static int conn_status = 0;
#define IP_ADDRESS ("192.168.207.131")
#define PORT (9099)
#include <iostream>
using namespace std;
int socket_tcp_alive(int socket)
{
	int ret = 0;

	int keep_alive = 1;
	ret = setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&keep_alive, sizeof(keep_alive));

	if (ret == SOCKET_ERROR)
	{
		printf("setsockopt failed: %d \n", WSAGetLastError());
		return -1;
	}

	struct tcp_keepalive in_keep_alive = { 0 };
	unsigned long ul_in_len = sizeof(struct tcp_keepalive);
	struct tcp_keepalive out_keep_alive = { 0 };
	unsigned long ul_out_len = sizeof(struct tcp_keepalive);
	unsigned long ul_bytes_return = 0;

	in_keep_alive.onoff = 1;                    /*打开keepalive*/
	in_keep_alive.keepaliveinterval = 5000;	/*发送keepalive心跳时间间隔-单位为毫秒*/
	in_keep_alive.keepalivetime = 1000;         /*多长时间没有报文开始发送keepalive心跳包-单位为毫秒*/

	ret = WSAIoctl(socket, SIO_KEEPALIVE_VALS, (LPVOID)&in_keep_alive, ul_in_len,
		(LPVOID)&out_keep_alive, ul_out_len, &ul_bytes_return, NULL, NULL);

	if (ret == SOCKET_ERROR)
	{
		printf("WSAIoctl failed: %d \n", WSAGetLastError());
		return -1;
	}

	return 0;
}
int tcp_connect_server()
{
	int save_errno;
	SOCKADDR_IN  server_addr;
	conn_status = 0;
	memset(&server_addr, 0, sizeof(server_addr));

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = inet_addr(IP_ADDRESS);
	server_addr.sin_port = htons(PORT);

	sockClient = ::socket(PF_INET, SOCK_STREAM, 0);
	if (sockClient == -1)
		return sockClient;


	conn_status = ::connect(sockClient, (struct sockaddr*)&server_addr, sizeof(server_addr));

	if (conn_status == -1)
	{
		save_errno = errno;   //清理  
		closesocket(sockClient);
		errno = save_errno; //the close may be error  
		return -1;
	}

	//	evutil_make_socket_nonblocking(sockfd);

	return sockClient;
}

DWORD WINAPI monitorThread(LPVOID pM)
{
	while (1)
	{
		char szRecvBuf[10] = { 0 };
	//	send(sockClient, "this is qiang ge1233", strlen("this is qiang ge1234") + 1, 0);
		int nRet = recv(sockClient, szRecvBuf, 1, MSG_PEEK); // 注意, 最后一个参数必须是MSG_PEEK, 否则会影响主线程接收信息
		if (nRet <= 0)
		{
			printf("监测到啦: nRet is %d\n", nRet);
			closesocket(sockClient);
			sockClient = NULL;
		  	sockClient = tcp_connect_server();
			if (conn_status != -1)
			socket_tcp_alive(sockClient);
		    
		 //	break;
		}
		Sleep(5000);

	}
	return 0;
}


void main()
{
	//加载套接字库,版本协商
	WORD wVersionRequired;
	WSADATA wsaData;
	int err;
	int status, save_errno;
	//请求库
	//WSAStartup( WORD wVersionRequired, WSADATA lpWSAData );
	wVersionRequired = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequired, &wsaData);

	if (err != 0)
	{
		//不等于0就退出
		return;
	}

	//高字节和低字节都不为1
	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return;
	}
	sockClient = socket(AF_INET, SOCK_STREAM, 0);
	//设定服务器的地址信息
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr = inet_addr(IP_ADDRESS);
	addrSrv.sin_family = AF_INET;
	addrSrv.sin_port = htons(PORT);
	while (1)
	{
		conn_status = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
		if (conn_status == -1)
	{
		save_errno = errno;   //清理  
 		errno = save_errno; //the close may be error  
		Sleep(3000);
		cout << "one lian test" << endl;
		continue;
	}
	else
	{
		socket_tcp_alive(sockClient);
		break;
	}
    
	}
	HANDLE handle = CreateThread(NULL, 0, monitorThread, NULL, 0, NULL);
   
//	send(sockClient, "this is qiang ge", strlen("this is qiang ge") + 1, 0);
	 
	getchar();
 
 

	closesocket(sockClient);
	WSACleanup();
	system("PAUSE");
}

  

上一篇:How do you do for your health of Site Office ?


下一篇:vue中keep-alive的用法及问题描述