Cplusplus封装好的windows64位系统下有共同基类TcpBase的TcpClient和TcpServer,拥有指定读多少个字节以及连接断开,自动重连,以及判断链接状态等接口的详细代码
时间: 2024-05-05 10:22:33 浏览: 90
以下是基于C++封装好的TcpClient和TcpServer类,它们都继承自TcpBase类,实现了指定读取字节数、连接断开、自动重连以及连接状态的判断等接口。
TcpBase.hpp
```c++
#ifndef TCPBASE_HPP
#define TCPBASE_HPP
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <cstdint>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <cerrno>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#endif
class TcpBase {
public:
TcpBase() = default;
virtual ~TcpBase() = default;
virtual void Connect(const std::string& ip, const uint16_t port);
virtual void Disconnect();
virtual bool IsConnected() const;
virtual void SetTimeout(const uint32_t timeout_ms);
virtual uint32_t GetTimeout() const;
protected:
virtual void OnConnected() {}
virtual void OnDisconnected() {}
virtual void OnReceived(const char* buf, const uint32_t len) {}
void Send(const char* buf, const uint32_t len);
void Send(const std::string& msg);
private:
void ThreadRecv();
protected:
//socket句柄
int32_t sockfd_ = -1;
private:
std::thread thread_recv_;
std::mutex mutex_;
std::condition_variable cond_;
bool is_connected_ = false;
uint32_t timeout_ms_ = 5000;
};
#endif
```
TcpBase.cpp
```c++
#include "TcpBase.hpp"
void TcpBase::Connect(const std::string& ip, const uint16_t port) {
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed!" << std::endl;
return;
}
#endif
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd_ < 0) {
std::cerr << "Socket failed!" << std::endl;
return;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(ip.c_str());
if (connect(sockfd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
std::cerr << "Connect failed!" << std::endl;
return;
}
is_connected_ = true;
OnConnected();
thread_recv_ = std::thread(&TcpBase::ThreadRecv, this);
}
void TcpBase::Disconnect() {
if (!is_connected_) {
return;
}
#ifdef _WIN32
closesocket(sockfd_);
WSACleanup();
#else
close(sockfd_);
#endif
is_connected_ = false;
OnDisconnected();
if (thread_recv_.joinable()) {
thread_recv_.join();
}
}
bool TcpBase::IsConnected() const {
return is_connected_;
}
void TcpBase::SetTimeout(const uint32_t timeout_ms) {
timeout_ms_ = timeout_ms;
}
uint32_t TcpBase::GetTimeout() const {
return timeout_ms_;
}
void TcpBase::Send(const char* buf, const uint32_t len) {
if (!is_connected_) {
return;
}
std::lock_guard<std::mutex> guard(mutex_);
const int32_t ret = send(sockfd_, buf, len, 0);
if (ret < 0) {
std::cerr << "Send failed! error code: " << errno << std::endl;
Disconnect();
}
}
void TcpBase::Send(const std::string& msg) {
Send(msg.c_str(), msg.length());
}
void TcpBase::ThreadRecv() {
const uint32_t buffer_size = 1024;
char buffer[buffer_size] = { 0 };
while (is_connected_) {
fd_set fd_read;
FD_ZERO(&fd_read);
FD_SET(sockfd_, &fd_read);
timeval timeout;
timeout.tv_sec = timeout_ms_ / 1000;
timeout.tv_usec = timeout_ms_ % 1000 * 1000;
const int32_t ret = select(sockfd_ + 1, &fd_read, nullptr, nullptr, &timeout);
if (ret < 0) {
std::cerr << "Select failed! error code: " << errno << std::endl;
Disconnect();
break;
}
if (ret == 0) {
continue;
}
const int32_t len = recv(sockfd_, buffer, buffer_size, 0);
if (len < 0) {
std::cerr << "Recv failed! error code: " << errno << std::endl;
Disconnect();
break;
}
if (len == 0) {
std::cerr << "Connection closed!" << std::endl;
Disconnect();
break;
}
OnReceived(buffer, len);
}
}
```
TcpClient.hpp
```c++
#ifndef TCPCLIENT_HPP
#define TCPCLIENT_HPP
#include "TcpBase.hpp"
class TcpClient : public TcpBase {
public:
TcpClient() = default;
virtual ~TcpClient() = default;
virtual void Connect(const std::string& ip, const uint16_t port) override;
virtual void Disconnect() override;
virtual void SetReadSize(const uint32_t size);
virtual uint32_t GetReadSize() const;
protected:
virtual void OnConnected() override;
virtual void OnDisconnected() override;
virtual void OnReceived(const char* buf, const uint32_t len) override;
private:
void ThreadReconnect();
private:
uint32_t read_size_ = 1024;
bool need_reconnect_ = true;
};
#endif
```
TcpClient.cpp
```c++
#include "TcpClient.hpp"
void TcpClient::Connect(const std::string& ip, const uint16_t port) {
need_reconnect_ = true;
while (need_reconnect_) {
TcpBase::Connect(ip, port);
if (is_connected_) {
break;
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void TcpClient::Disconnect() {
need_reconnect_ = false;
TcpBase::Disconnect();
}
void TcpClient::SetReadSize(const uint32_t size) {
read_size_ = size;
}
uint32_t TcpClient::GetReadSize() const {
return read_size_;
}
void TcpClient::OnConnected() {
std::cout << "TcpClient connected!" << std::endl;
}
void TcpClient::OnDisconnected() {
std::cout << "TcpClient disconnected!" << std::endl;
if (need_reconnect_) {
thread_recv_.detach();
thread_recv_ = std::thread(&TcpClient::ThreadReconnect, this);
}
}
void TcpClient::OnReceived(const char* buf, const uint32_t len) {
std::cout << "TcpClient received: " << std::string(buf, len) << std::endl;
}
void TcpClient::ThreadReconnect() {
std::this_thread::sleep_for(std::chrono::seconds(1));
Connect("", 0);
}
```
TcpServer.hpp
```c++
#ifndef TCPSERVER_HPP
#define TCPSERVER_HPP
#include "TcpBase.hpp"
class TcpServer : public TcpBase {
public:
TcpServer() = default;
virtual ~TcpServer() = default;
virtual void Connect(const std::string& ip, const uint16_t port) override;
virtual void Disconnect() override;
virtual void SetReadSize(const uint32_t size);
virtual uint32_t GetReadSize() const;
void SetMaxConnections(const uint32_t max_connections);
uint32_t GetMaxConnections() const;
protected:
virtual void OnConnected() override;
virtual void OnDisconnected() override;
virtual void OnReceived(const char* buf, const uint32_t len) override;
private:
void ThreadAccept();
private:
uint16_t port_ = 0;
uint32_t read_size_ = 1024;
uint32_t max_connections_ = 10;
std::vector<int32_t> vec_sockfd_;
};
#endif
```
TcpServer.cpp
```c++
#include "TcpServer.hpp"
void TcpServer::Connect(const std::string& ip, const uint16_t port) {
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed!" << std::endl;
return;
}
#endif
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd_ < 0) {
std::cerr << "Socket failed!" << std::endl;
return;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
std::cerr << "Bind failed!" << std::endl;
return;
}
if (listen(sockfd_, max_connections_) < 0) {
std::cerr << "Listen failed!" << std::endl;
return;
}
is_connected_ = true;
OnConnected();
thread_recv_ = std::thread(&TcpServer::ThreadAccept, this);
}
void TcpServer::Disconnect() {
for (const auto sockfd : vec_sockfd_) {
#ifdef _WIN32
closesocket(sockfd);
#else
close(sockfd);
#endif
}
vec_sockfd_.clear();
#ifdef _WIN32
closesocket(sockfd_);
WSACleanup();
#else
close(sockfd_);
#endif
is_connected_ = false;
OnDisconnected();
if (thread_recv_.joinable()) {
thread_recv_.join();
}
}
void TcpServer::SetReadSize(const uint32_t size) {
read_size_ = size;
}
uint32_t TcpServer::GetReadSize() const {
return read_size_;
}
void TcpServer::SetMaxConnections(const uint32_t max_connections) {
max_connections_ = max_connections;
}
uint32_t TcpServer::GetMaxConnections() const {
return max_connections_;
}
void TcpServer::OnConnected() {
std::cout << "TcpServer listening on port " << port_ << "!" << std::endl;
}
void TcpServer::OnDisconnected() {
std::cout << "TcpServer stopped!" << std::endl;
}
void TcpServer::OnReceived(const char* buf, const uint32_t len) {
std::cout << "TcpServer received: " << std::string(buf, len) << std::endl;
}
void TcpServer::ThreadAccept() {
const uint32_t buffer_size = 1024;
char buffer[buffer_size] = { 0 };
while (is_connected_) {
const int32_t sockfd = accept(sockfd_, nullptr, nullptr);
if (sockfd < 0) {
std::cerr << "Accept failed! error code: " << errno << std::endl;
Disconnect();
break;
}
std::cout << "New connection established!" << std::endl;
vec_sockfd_.push_back(sockfd);
const std::thread thread_recv = std::thread([sockfd, this]() {
while (true) {
const int32_t len = recv(sockfd, buffer, buffer_size, 0);
if (len < 0) {
std::cerr << "Recv failed! error code: " << errno << std::endl;
break;
}
if (len == 0) {
std::cerr << "Connection closed!" << std::endl;
break;
}
OnReceived(buffer, len);
}
for (auto iter = vec_sockfd_.begin(); iter != vec_sockfd_.end(); iter++) {
if (*iter == sockfd) {
vec_sockfd_.erase(iter);
break;
}
}
#ifdef _WIN32
closesocket(sockfd);
#else
close(sockfd);
#endif
});
thread_recv.detach();
}
}
```
阅读全文