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;
}