[C++][工具分享]ANTCP(LITE版)

1.使用

#include "stdafx.h"
#include "AnTcp.h"

int main()
{
	AnTcp *pTcp = AnTcp::GetTcp();
	pTcp->SetMode(AnTCPMode::MODE_CLIENT);
	pTcp->Open(9000, "127.0.0.1");
	bool FirstRun = true;
	while (true)
	{
		if (pTcp->getVisible() && FirstRun)
		{
			FirstRun = false;
			pTcp->SendMsg("Ready", 5);
			pTcp->SendMsg("AF AB FF",8, AnTCPEncode::ENCODE_HEX);
		}
		if (pTcp->getVisible() && !FirstRun)
		{
			char buffer[1024];
			memset(buffer, NULL, 1024);
			int size = 0;
			pTcp->RecvMsg(buffer, size,AnTCPEncode::ENCODE_HEX);
			if (size > 0)
			{
				printf("%s\n", buffer);
			}
		}
	}
}

2.类

AnTcp.h

#pragma once
//vs报错时请在属性-->C/C++-->预处理器里填写_WINSOCK_DEPRECATED_NO_WARNINGS
#include <string>
#include <iostream>
#include <winsock2.h>


#pragma comment (lib, "ws2_32.lib")

enum AnTCPError
{
	TCP_ERROR = -1,
	TCP_SUCCESS = 0,
	TCP_MODEERROR,
	TCP_PARAMERROR,
	TCP_BINDERROR,
	TCP_LISTENERROR
};

enum AnTCPMode
{
	MODE_UNUSE=-1,
	MODE_CLIENT,
	MODE_SERVER
};

enum AnTCPEncode
{
	ENCODE_ASCII=0,
	ENCODE_HEX
};

class AnTcp
{
protected:
	AnTcp();
	~AnTcp();

public:
	//获取静态指针
	static AnTcp *GetTcp();

	//tcp通信模式,这个必须在open之前调用
	int SetMode(AnTCPMode mode);
	int GetMode(AnTCPMode &mode);

	//打开和关闭tcp功能
	int Open(int Port, const char *Ip = nullptr);
	int Close();

	//消息,接收和发送,可以选择ascii码或者16进制
	int SendMsg(const char *msg, int size, AnTCPEncode code= AnTCPEncode::ENCODE_ASCII);
	int RecvMsg(char *msg,int &size, AnTCPEncode code = AnTCPEncode::ENCODE_ASCII);

	//是否可用,对于服务器来说有链接,对于客户端链接服务器
	bool getVisible() { return m_IsSockEnable;}
protected:
	void Connecting();//客户端链接服务器线程
	void Waitting();//服务器等待客户端链接线程
	static DWORD WINAPI ThreadOpen(LPVOID lpThreadParameter);
private:
	//socket info
	SOCKET      m_ServerSock;
	SOCKET      m_ClientSock;
	WSADATA     m_WsaData;
	sockaddr_in m_SockAddr;
	//mode
	AnTCPMode   m_TCPMode;
	//param
	bool        m_IsOpened;
	bool        m_IsSockEnable;
};

AnTcp.cpp

#include "stdafx.h"
#include "AnTcp.h"
#include <algorithm>

//socket状态检测
bool SocketCheck(SOCKET sock);

//16进制样式的ascii码字符串转16进制
//例,Ascii2Hex("AF 01 0A");
std::string Ascii2Hex(const char *ascii);

//16进制字符串转ascii码,autoSpace:自动追加空格
std::string Hex2Ascii(const char *hex,bool autoSpace=true);

AnTcp::AnTcp()
{
	WSAStartup(MAKEWORD(2, 2), &m_WsaData);
	m_ServerSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	m_ClientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	memset(&m_SockAddr, 0, sizeof(m_SockAddr));
	//init data
	m_TCPMode = AnTCPMode::MODE_UNUSE;
	m_IsOpened = false;
	m_IsSockEnable = false;
}

AnTcp::~AnTcp()
{
	Close();
}

AnTcp * AnTcp::GetTcp()
{
	static AnTcp tcp;
	return &tcp;
}

int AnTcp::SetMode(AnTCPMode mode)
{
	m_TCPMode = mode;
	m_SockAddr.sin_family = AF_INET;//把这个放在这里主要是想让你一定要调用这个
	return TCP_SUCCESS;
}

int AnTcp::GetMode(AnTCPMode &mode)
{
	mode = m_TCPMode;
	return TCP_SUCCESS;
}

int AnTcp::Open(int Port, const char * Ip)
{
	if (m_TCPMode == AnTCPMode::MODE_UNUSE)
		return TCP_MODEERROR;
	if (m_IsOpened)
		return TCP_SUCCESS;

	AnTCPError error= AnTCPError::TCP_ERROR;
	//
	switch (m_TCPMode)
	{
		case MODE_UNUSE:
			error = AnTCPError::TCP_ERROR;
			break;
		case MODE_CLIENT:
		{
			if (!Ip|| Port<0)
			{
				error = AnTCPError::TCP_PARAMERROR;
				break;
			}
			m_SockAddr.sin_port = htons(Port);
			m_SockAddr.sin_addr.s_addr = inet_addr(Ip);
			CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadOpen, this, 0, NULL);
			error = AnTCPError::TCP_SUCCESS;
			break;
		}
		case MODE_SERVER:
		{
			m_SockAddr.sin_port = htons(Port);
			m_SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
			if (::bind(m_ServerSock, (sockaddr*)&m_SockAddr, sizeof(m_SockAddr)) == SOCKET_ERROR)
			{
				error= AnTCPError::TCP_BINDERROR;
				break;
			}
			if (listen(m_ServerSock, 2) == SOCKET_ERROR)
			{
				error = AnTCPError::TCP_LISTENERROR;
				break;
			}
			CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadOpen, this, 0, NULL);
			error = AnTCPError::TCP_SUCCESS;
			break;
		}
		default:
			break;
	}

	if (error== AnTCPError::TCP_SUCCESS)
	{
		m_IsOpened = true;
	}
	return error;
}

int AnTcp::Close()
{
	closesocket(m_ServerSock);
	closesocket(m_ClientSock);
    //终止 DLL 的使用
	WSACleanup();
	return TCP_SUCCESS;
}

int AnTcp::SendMsg(const char * msg, int size, AnTCPEncode code)
{
	if (!m_IsOpened || !m_IsSockEnable)
		return TCP_ERROR;
	if (m_TCPMode == AnTCPMode::MODE_UNUSE)
		return TCP_MODEERROR;
	//发送之前做个心跳包检测
	if (!SocketCheck(m_ClientSock))
	{
		m_IsSockEnable = false;
		return TCP_ERROR;
	}
	if (code ==AnTCPEncode::ENCODE_HEX)
	{
		std::string Hexstr = Ascii2Hex(msg);
		//发送信息
		::send(m_ClientSock, Hexstr.c_str(), Hexstr.length(), NULL);
		return TCP_SUCCESS;
	}
	//发送信息
	::send(m_ClientSock, msg, size, NULL);
	return TCP_SUCCESS;
}

int AnTcp::RecvMsg(char * msg, int & size, AnTCPEncode code)
{
	if (!m_IsOpened || !m_IsSockEnable)
		return TCP_ERROR;
	if (m_TCPMode == AnTCPMode::MODE_UNUSE)
		return TCP_MODEERROR;
	//接收之前不能做心跳包检测,否则接收不到任何消息
	//先给一个定值
	int MXASIZE = 10240;
	if (size>MXASIZE)
	{
		MXASIZE = size;
		size = 0;
	}
	if (code == AnTCPEncode::ENCODE_HEX)
	{
		size = ::recv(m_ClientSock, msg, MXASIZE, NULL);
		if (size > 0)
		{
			std::string Hexstr = Hex2Ascii(msg);
			memset(msg,NULL,sizeof(msg));
			memcpy(msg, Hexstr.c_str(), Hexstr.length());
		}
		return TCP_SUCCESS;
	}
	//接收
	size = ::recv(m_ClientSock, msg, MXASIZE, NULL);
	return TCP_SUCCESS;
}

void AnTcp::Connecting()
{
	while (true)
	{
		if (connect(m_ClientSock, (SOCKADDR*)&m_SockAddr, sizeof(SOCKADDR)) != SOCKET_ERROR)
		{
			m_IsSockEnable = true;
			return;
		}
	}
}

void AnTcp::Waitting()
{
	SOCKADDR clntAddr;
	int nSize = sizeof(SOCKADDR);
	while (true)
	{
		m_ClientSock = ::accept(m_ServerSock, (SOCKADDR*)&clntAddr, &nSize);
		if (m_ClientSock!=INVALID_SOCKET)
		{
			m_IsSockEnable = true;
		}
	}
}

DWORD AnTcp::ThreadOpen(LPVOID lpThreadParameter)
{
	switch (((AnTcp*)lpThreadParameter)->m_TCPMode)
	{
		case MODE_CLIENT:
		{
			((AnTcp*)lpThreadParameter)->Connecting();
			break;
		}
		case MODE_SERVER:
		{
			((AnTcp*)lpThreadParameter)->Waitting();
			break;
		}
		default:
			break;
	}
	return 0;
}

bool SocketCheck(SOCKET sock)
{
	//当使用 select()函数测试一个socket是否可读时,如果select()函数返回值为1,
	//且使用recv()函数读取的数据长度为0 时,就说明该socket已经断开
	char buff[20];
	memset(buff, NULL, sizeof(char) * 20);
	struct timeval timeout = { 1, 0 };
	fd_set rdfs;
	FD_ZERO(&rdfs);
	FD_SET(sock, &rdfs);
	int re = select(sock + 1, &rdfs, NULL, NULL, &timeout);
	if (re > 0)
	{
		int recvLen = recv(sock, buff, sizeof(buff), 0);
		if (recvLen > 0)
		{
			//printf("socket connected\n");
			return true;
		}
		else if (recvLen < 0)
		{
			if (errno == EINTR)
			{
				//printf("socket connected\n");
				return true;
			}
			else
			{
				//printf("socket disconnected! connect again!\n");
				return false;
			}
		}
		else if (recvLen == 0)
		{
			//printf("socket disconnected!connect again\n");
			return false;
		}
	}
	else if (re == 0)
	{
		//time out
		//printf("socket connected\n");
		return true;
	}
	else if (re < 0)
	{
		if (errno == EINTR)
		{
			//printf("socket connected\n");
			return true;
		}
		else
		{
			//printf("socket disconnected ! connect again!\n");
			return false;
		}
	}
}

std::string Ascii2Hex(const char * ascii)
{
	std::string result = "";
	//
	std::string asciiStr = ascii;
	//全转换大写
	std::transform(asciiStr.begin(), asciiStr.end(), asciiStr.begin(), ::toupper);
	//剔除不合法字符 0-9 a-f,空格等
	for (int i = 0; i<asciiStr.length();i++)
	{
		bool is_legal = ((asciiStr.at(i) >= '0') && (asciiStr.at(i) <= '9')) || ((asciiStr.at(i) >= 'A') && (asciiStr.at(i) <= 'F'));
		if (!is_legal)
			asciiStr.erase(i,1);//剔除
	}
    //
	if (asciiStr.length() % 2 != 0)//字符应该是2的倍数
		return result;

	//重新组合
	const char *hex = "0123456789ABCDEF";
	for (int i = 0; i<asciiStr.length() / 2; i++)
	{
		int leftInt = strchr(hex, toupper(asciiStr.at(i * 2))) - hex;
		int rightInt = strchr(hex, toupper(asciiStr.at(i * 2 + 1))) - hex;
		unsigned char re = leftInt * 16 + rightInt;
		result += re;
	}

	return result;
}

std::string Hex2Ascii(const char * hex, bool autoSpace)
{
	std::string result = "";
	//
	std::string hexStr = hex;
	//
	for (int i = 0; i < hexStr.length(); i++)
	{
		int temp = (hexStr.at(i) & 0xF0) >> 4;
		if (temp < 10)
			result += (char)(temp + '0');
		else
			result += (char)(temp + 'A' - 10);

		temp = hexStr.at(i) & 0x0F;
		if (temp < 10)
			result += (char)(temp + '0');
		else
			result += (char)(temp + 'A' - 10);
		if (autoSpace)
		{
			if (i != hexStr.length() - 1)
			{
				result += " ";
			}
		}
	}
	return result;
}

猜你喜欢

转载自blog.csdn.net/qq_36251561/article/details/115541354