封装一个TCP客户端类

TCPClient

写一个Windows环境下的TCP客户端,功能比较简单。
创建一个对象,即可连上服务器;并应用了一个有限状态机,在与服务器断开连接时,会自动尝试与服务器建立连接;在接收发送数据上,仅做测试通讯是否正常,被动接收数据,然后再把数据发送回给服务器;其中用到的my_std_thread.h,在另一篇文章有介绍


TcpClient.h

#pragma once
#include <WinSock2.h>
#include <stdio.h>
#include "my_std_thread.h"
using namespace std;

class TcpClient
{
private:
	SOCKET					sclient_ = INVALID_SOCKET;	
	const char*				ip_ = NULL;					
	u_short					port_ = 0;
private:
	my_std_thread			my_thread_;  
	my_std_thread::Thread   thread_id_;			
	int						link_step_;			
	my_std_thread::Mutex    link_step_mutex_;	
	my_std_thread::Mutex    send_mutex_;		

private:

	/*************************************************
	 * 函数名: 线程函数
	 * 描述 : 开启线程
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : 无
	*************************************************/
	void ThreadWhile(void* arg);
	/*************************************************
	 * 函数名: 连接服务器
	 * 描述 :
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : true/false
	*************************************************/
	bool LinkServer();
	/*************************************************
	 * 函数名: 初始化
	 * 描述 : 准备TCP通讯所需的环境
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : 0/1
	*************************************************/
	int Initialize();
	/*************************************************
	 * 函数名: 开始
	 * 描述 : 客户端开始运行
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : true
	*************************************************/
	bool Start();
public:
	/*************************************************
	 * 函数名: 
	 * 描述 :连接状态
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : true表示连接上,false表示已断开
	*************************************************/
	bool ConnectStatus();
	/*************************************************
	 * 函数名: 
	 * 描述 : 给服务器发送数据
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : 1/0
	*************************************************/
	int Send(const char* buffer, int len);
	/*************************************************
	 * 函数名: 发送
	 * 描述 : 构造函数
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : 
	*************************************************/
	TcpClient(const char* ip, u_short port);
	/*************************************************
	 * 函数名: 
	 * 描述 : 析构函数
	 * 输入 : 无
	 * 输出 : 无
	 * 返回值 : 
	*************************************************/
	~TcpClient();
};



TcpClient.h

#include "TCPClient.h"
#include <string>
#include <iostream>
#include <thread>
#pragma comment(lib,"ws2_32.lib")
using namespace std;



/*************************************************
 * 函数名: 初始化 
 * 描述 : 准备TCP通讯所需的环境
 * 输入 : 无
 * 输出 : WSAStartup Failed/Success 
 * 返回值 : 0/1
*************************************************/
int TcpClient::Initialize() {

	WORD version = MAKEWORD(2, 2);
	WSADATA data;
	
	if (WSAStartup(version, &data) != 0) {
		std::cout << "WSAStartup Failed!"<<std::endl;
		return 0;
	}
	
	std::cout << "WSAStartup Success!"<<std::endl;
	return 1;
//	return 1;
}



/*************************************************
 * 函数名: 开始
 * 描述 : 客户端开始运行
 * 输入 : 无
 * 输出 : 无
 * 返回值 : true
*************************************************/

bool TcpClient::Start() {
	
	this->Initialize();

	my_thread_.createThread(thread_id_, &TcpClient::ThreadWhile,this,NULL);
	return true;
}

/*************************************************
 * 函数名: 连接服务器
 * 描述 :
 * 输入 : 无
 * 输出 : 无
 * 返回值 : true/false
*************************************************/

bool TcpClient::LinkServer()
{
	bool ret = false;
	if (sclient_>0) {
		closesocket(sclient_);
	}
	sclient_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	sockaddr_in servAddr;
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(port_);
	servAddr.sin_addr.S_un.S_addr = inet_addr(ip_);

	if (connect(sclient_, (LPSOCKADDR)&servAddr, sizeof(servAddr)) == SOCKET_ERROR )
	{
		std::cout << "Connect Failed!" << std::endl;
		ret = false;
	}
	else {
		std::cout << "Connect Success!" << std::endl;
		ret = true;
	}
	return ret;
}


/*************************************************
 * 函数名: 发送
 * 描述 : 给服务器发送数据
 * 输入 : 无
 * 输出 : 无
 * 返回值 : 1/0
*************************************************/

int TcpClient::Send(const char* buffer, int len) {
	if (!ConnectStatus()) {
		return -1;
	}
	my_thread_.lock(send_mutex_);
	int flag = send(sclient_,buffer,len,0);
	my_thread_.unlock(send_mutex_);
	if (flag== len) {
		std::cout << "Send Success!" << std::endl;
		return 1;
	}
	std::cout << "Send Failed!" << std::endl;
	return 0;
}

/*************************************************
 * 函数名: 连接状态
 * 描述 : 
 * 输入 : 无
 * 输出 : 无
 * 参数 : 无
 * 返回值 : true表示连接上,false表示已断开
*************************************************/
bool TcpClient::ConnectStatus() {
	bool ret = false;
	my_thread_.lock(link_step_mutex_);
	if (link_step_>0) {
		ret=  true;
	}
	my_thread_.unlock(link_step_mutex_);
	return ret;
}


/*************************************************
 * 函数名: 线程函数
 * 描述 : 类内开启线程
 * 输入 : 无
 * 输出 : 无
 * 参数 : 无
 * 返回值 : 无
*************************************************/

void TcpClient::ThreadWhile(void* arg)
{
	unsigned char buffer[4096] = { 0 };
	int ret = 0;

	while (1) {
		switch (link_step_) {
		case 0:
			if (LinkServer()) {
				link_step_++;
				break;
			}
			break;
		case 1:
			ret = recv(sclient_, (char*)buffer, sizeof(buffer), 0);
			// -1 接收失败  0 断开连接 
			if (ret <= 0) {
				link_step_ = 0;
				break;
			}
			else {
				Send((char*)buffer,ret);
			}
			break;
		default:
			break;
		}
	}
}

/*************************************************
 * 函数名: 
 * 描述 : 构造函数
 * 输入 : 无
 * 输出 : 无
 * 返回值 :
*************************************************/
TcpClient::TcpClient(const char* ip, u_short port) {
	
	ip_ = ip;
	port_ = port;

	thread_id_ = NULL;
	link_step_mutex_ = NULL;
	send_mutex_ = NULL;
	my_thread_.createMutex(link_step_mutex_);
	my_thread_.createMutex(send_mutex_);
	link_step_ = 0;
	sclient_ = INVALID_SOCKET;
	Start();
}

/*************************************************
 * 函数名:
 * 描述 : 析构函数
 * 输入 : 无
 * 输出 : 无
 * 返回值 :
*************************************************/
TcpClient::~TcpClient() {
	if (sclient_ != INVALID_SOCKET) {
		closesocket(sclient_);
	}
	my_thread_.deleteMutex(link_step_mutex_);
	my_thread_.deleteMutex(send_mutex_);
	WSACleanup();
	sclient_ = INVALID_SOCKET;
}

上一篇:gridview checkbox从服务器端和客户端两个方面实现全选和反选


下一篇:checkbox之checked的方法(attr和prop)区别