📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨


文章目录
- 🏳️🌈一、TcpService.hpp
-
- [1.1 TcpService类](#1.1 TcpService类)
- [1.2 构造、析构函数](#1.2 构造、析构函数)
- [1.3 Loop() 循环函数](#1.3 Loop() 循环函数)
- 🏳️🌈二、Service.hpp
-
- 2.1、IOService类基本结构
- [2.2 构造函数、析构函数](#2.2 构造函数、析构函数)
- [2.3 IOSExcute()](#2.3 IOSExcute())
- 🏳️🌈三、TcpServer.cpp
- 👥总结
上一篇文章简单的将 Socket
类进行了封装,封装的目的是为了我们后序直接使用的,因此这篇文章使用封装好的Socket类实现网络计算器(加协议版本)的一部分轮廓,此处我们将执行方法单独放在一个文件!
🏳️🌈一、TcpService.hpp
我们这里使用 TcpServer 的多线程版本,如有其他版本的需要,可移步 传送门
1.1 TcpService类
TcpServer类成员变量 有端口号,监听套接字(封装的智能指针类型),运行状态和执行方法,构造函数初始化成员变量即可!
namespace TcpServerModule{
using namespace SocketModule;
using namespace LogModule;
using service_t = std::function<void(SocketModule::SockPtr, InetAddr&)>;
class TcpServer{
public:
TcpServer(service_t service, uint16_t port){}
void Loop(){}
~TcpServer(){}
private:
uint16_t port;
SockPtr _listensock;
bool _isrunning;
service_t _service;
};
}
1.2 构造、析构函数
构造函数 初始化成员变量并创建监听套接字(调用父类方法),析构函数无需处理!
TcpServer(service_t service, uint16_t port)
: _port(port), _listensock(std::make_shared<TcpSocket>()),
_isrunning(false), _service(service) {
_listensock->BuildListenSocket(port);
}
~TcpServer() {}
1.3 Loop() 循环函数
Loop()函数使用多线程的版本执行长服务,让新线程去执行主函数传递的执行方法!
void Loop() {
_isrunning = true;
while (_isrunning) {
InetAddr client;
// 获取客户端连接
SockPtr cli = _listensock->Accepter(&client);
if (cli == nullptr)
continue;
LOG(LogLevel::DEBUG)
<< "get a new connection from " << client.AddrStr().c_str();
// 获取成功
pthread_t tid;
// ThreadData 的头文件是
ThreadData* td = new ThreadData(cli, this, client);
pthread_create(&tid, nullptr, Execute, td); // 新线程分离
}
}
// 线程函数参数对象
class ThreadData {
public:
SockPtr _sockfd;
TcpServer* _self;
InetAddr _addr;
public:
ThreadData(SockPtr sockfd, TcpServer* self, const InetAddr& addr)
: _sockfd(sockfd), _self(self), _addr(addr) {}
};
// 线程函数
static void* Execute(void* args) {
ThreadData* td = static_cast<ThreadData*>(args);
// 子线程结束后由系统自动回收资源,无需主线程调用 pthread_join
pthread_detach(pthread_self()); // 分离新线程,无需主线程回收
td->_self->_service(td->_sockfd, td->_addr);
delete td;
return nullptr;
}
🏳️🌈二、Service.hpp
该文件设计一个类,其中一个成员函数实现执行方法 ,暂时先让服务端代码编译过即可,后序再加协议!
2.1、IOService类基本结构
class IOService{
public:
IOService();
void IOExcute(SockPtr sock, InetAddr& addr);
~IOService();
};
2.2 构造函数、析构函数
这个类没有成员变量,所以这两部分不需要处理
2.3 IOSExcute()
该函数时
TcpServer
中执行方法的具体实现,此处暂时只进行IO操作,保证编译通过
void IOExcute(SockPtr sock, InetAddr& addr) {
while (true) {
std::string message;
// ssize_t Recv(std::string* out) override{}
ssize_t n = sock->Recv(&message);
if (n > 0) {
LOG(LogLevel::INFO) << "get message: " << message << "from"
<< addr.AddrStr().c_str();
std::string rsp = "response test";
sock->Send(rsp);
} else if (n == 0) {
LOG(LogLevel::INFO)
<< "client " << addr.AddrStr().c_str() << " disconnected";
break;
} else {
LOG(LogLevel::ERROR)
<< "recv error for client: " << addr.AddrStr().c_str();
break;
}
}
}
🏳️🌈三、TcpServer.cpp
创建TcpServer类对象,并调用执行函数运行服务端!
#include "TcpServer.hpp"
#include "Service.hpp"
using namespace TcpServerModule;
int main(int argc, char* argv[]){
if(argc != 2){
std::cerr << "Usage: " << argv[0] << " port" << std::endl;
Die(1);
}
uint16_t port = std::stoi(argv[1]);
IOService service;
std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(
std::bind(&IOService::IOExcute, &service, std::placeholders::_1, std::placeholders::_2),
port);
tsvr->Loop();
return 0;
}
👥总结
本篇博文对 【Linux网络】TCP服务中IOService应用与实现 做了一个较为详细的介绍,不知道对你有没有帮助呢
觉得博主写得还不错的三连支持下吧!会继续努力的~