Files
Netralib/src/Netra.cpp
2025-07-17 15:23:35 +08:00

185 lines
5.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Netra.hpp"
namespace QCL
{
TcpServer::TcpServer(int port)
: port_(port), running_(false), serverSock_(-1) {}
/**
* @brief 析构函数中调用stop()确保服务器资源被释放
*/
TcpServer::~TcpServer()
{
stop();
}
/**
* @brief 启动服务器:
* 1. 创建监听socketTCP
* 2. 绑定端口
* 3. 监听端口
* 4. 启动监听线程acceptThread_
*
* @return 成功返回true失败返回false
*/
bool TcpServer::start()
{
// 创建socket
serverSock_ = socket(AF_INET, SOCK_STREAM, 0);
if (serverSock_ < 0)
{
std::cerr << "Socket 创建失败\n";
return false;
}
// 设置socket地址结构
sockaddr_in serverAddr;
std::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port_); // 端口转网络字节序
serverAddr.sin_addr.s_addr = INADDR_ANY; // 监听所有网卡IP
// 允许端口重用,防止服务器异常关闭后端口被占用
int opt = 1;
setsockopt(serverSock_, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
// 绑定端口
if (bind(serverSock_, (sockaddr *)&serverAddr, sizeof(serverAddr)) < 0)
{
std::cerr << "绑定失败\n";
return false;
}
// 开始监听最大等待连接数为5
if (listen(serverSock_, 5) < 0)
{
std::cerr << "监听失败\n";
return false;
}
// 设置运行标志为true
running_ = true;
// 启动专门接受客户端连接的线程
acceptThread_ = std::thread(&TcpServer::acceptClients, this);
std::cout << "服务器启动,监听端口:" << port_ << std::endl;
return true;
}
/**
* @brief 停止服务器:
* 1. 设置运行标志为false通知线程退出
* 2. 关闭监听socket
* 3. 关闭所有客户端socket清理客户端列表
* 4. 等待所有线程退出
*/
void TcpServer::stop()
{
running_ = false;
if (serverSock_ >= 0)
{
close(serverSock_);
serverSock_ = -1;
}
{
// 线程安全关闭所有客户端socket
std::lock_guard<std::mutex> lock(clientsMutex_);
for (int sock : clientSockets_)
{
close(sock);
}
clientSockets_.clear();
}
// 等待监听线程退出
if (acceptThread_.joinable())
acceptThread_.join();
// 等待所有客户端处理线程退出
for (auto &t : clientThreads_)
{
if (t.joinable())
t.join();
}
std::cout << "服务器已停止\n";
}
/**
* @brief acceptClients函数循环监听客户端连接请求
* 每当accept成功
* 1. 打印客户端IP和Socket信息
* 2. 线程安全地将客户端Socket加入clientSockets_列表
* 3. 创建新线程调用handleClient处理该客户端收发
*/
void TcpServer::acceptClients()
{
while (running_)
{
sockaddr_in clientAddr;
socklen_t clientLen = sizeof(clientAddr);
int clientSock = accept(serverSock_, (sockaddr *)&clientAddr, &clientLen);
if (clientSock < 0)
{
if (running_)
std::cerr << "接受连接失败\n";
continue;
}
// 将客户端IP转换成字符串格式打印
char clientIP[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(clientAddr.sin_addr), clientIP, INET_ADDRSTRLEN);
std::cout << "客户端连接IP: " << clientIP << ", Socket: " << clientSock << std::endl;
{
// 加锁保护共享的clientSockets_容器
std::lock_guard<std::mutex> lock(clientsMutex_);
clientSockets_.push_back(clientSock);
}
}
}
/**
* @brief 发送消息给指定客户端
* @param clientSock 客户端socket
* @param message 发送消息内容
*/
void TcpServer::sendToClient(int clientSock, const std::string &message)
{
send(clientSock, message.c_str(), message.size(), 0);
}
/**
* @brief 单次接收指定客户端数据
* @param clientSock 客户端socket
*
* 注意:此函数在当前设计中未在线程中使用,仅演示用。
*/
char *TcpServer::receiveFromClient(int clientSock)
{
char buffer[1024];
std::memset(buffer, 0, sizeof(buffer));
ssize_t bytesReceived = recv(clientSock, buffer, sizeof(buffer) - 1, 0);
if (bytesReceived <= 0)
{
std::cerr << "接收数据失败或客户端断开连接\n";
return nullptr;
}
return strdup(buffer); // 返回动态分配的字符串副本
}
/**
* @brief 获取当前所有客户端Socket副本线程安全
* @return 包含所有客户端socket的vector副本
*/
std::vector<int> TcpServer::getClientSockets()
{
std::lock_guard<std::mutex> lock(clientsMutex_);
return clientSockets_;
}
}