网络编程框架笔记

一、项目整体结构

1.1 文件构成

复制代码
- Common.hpp          // 通用定义和基类
- InetAddr.hpp        // 地址处理类
- Mutex.hpp           // 互斥锁模块
- Log.hpp             // 日志系统
- Socket.hpp          // Socket抽象和实现

1.2 命名空间组织

复制代码
namespace MutexModule    // 互斥锁相关
namespace LogModule      // 日志系统
namespace SocketModule   // Socket封装

二、Common.hpp - 基础定义

2.1 错误码枚举

复制代码
enum ExitCode {
    OK = 0,         // 正常
    USAGE_ERR,      // 使用错误
    SOCKET_ERR,     // socket创建失败
    BIND_ERR,       // bind失败
    LISTEN_ERR,     // listen失败
    CONNECT_ERR,    // connect失败
    FORK_ERR        // fork失败
};

2.2 禁止拷贝基类

复制代码
class NoCopy {
public:
    NoCopy() {}
    ~NoCopy() {}
    NoCopy(const NoCopy &) = delete;              // 禁止拷贝构造
    const NoCopy &operator=(const NoCopy&) = delete; // 禁止赋值
};

2.3 宏定义

复制代码
#define CONV(addr) ((struct sockaddr*)&addr)  // sockaddr_in转sockaddr*

三、InetAddr.hpp - 网络地址封装

3.1 类定义

复制代码
class InetAddr {
private:
    struct sockaddr_in _addr;  // 网络地址结构
    std::string _ip;           // 字符串格式IP
    uint16_t _port;            // 端口号
};

3.2 构造函数

复制代码
// 1. 默认构造
InetAddr() {}

// 2. 从sockaddr_in构造
InetAddr(struct sockaddr_in &addr) {
    SetAddr(addr);
}

// 3. 指定IP和端口
InetAddr(const std::string &ip, uint16_t port) 
    : _ip(ip), _port(port) {
    // 主机字节序 -> 网络字节序
    memset(&_addr, 0, sizeof(_addr));
    _addr.sin_family = AF_INET;
    inet_pton(AF_INET, _ip.c_str(), &_addr.sin_addr);
    _addr.sin_port = htons(_port);
}

// 4. 仅指定端口(监听所有IP)
InetAddr(uint16_t port) : _port(port), _ip() {
    memset(&_addr, 0, sizeof(_addr));
    _addr.sin_family = AF_INET;
    _addr.sin_addr.s_addr = INADDR_ANY;  // 0.0.0.0
    _addr.sin_port = htons(_port);
}

3.3 核心方法

复制代码
// 设置地址(从accept接收)
void SetAddr(struct sockaddr_in &addr) {
    _addr = addr;
    _port = ntohs(_addr.sin_port);           // 网络->主机
    char ipbuffer[64];
    inet_ntop(AF_INET, &_addr.sin_addr, ipbuffer, sizeof(_addr));
    _ip = ipbuffer;                          // 网络IP->字符串IP
}

// 获取各种格式的地址
uint16_t Port() { return _port; }
std::string Ip() { return _ip; }
const struct sockaddr_in &NetAddr() { return _addr; }
const struct sockaddr *NetAddrPtr() { return CONV(_addr); }
socklen_t NetAddrLen() { return sizeof(_addr); }

// 格式化输出
std::string StringAddr() {
    return _ip + ":" + std::to_string(_port);
}

四、Mutex.hpp - 线程同步

4.1 互斥锁类

复制代码
class Mutex {
private:
    pthread_mutex_t _mutex;
    
public:
    Mutex() { pthread_mutex_init(&_mutex, nullptr); }
    ~Mutex() { pthread_mutex_destroy(&_mutex); }
    void Lock() { pthread_mutex_lock(&_mutex); }
    void Unlock() { pthread_mutex_unlock(&_mutex); }
    pthread_mutex_t *Get() { return &_mutex; }
};

4.2 自动锁守卫(RAII)

复制代码
class LockGuard {
private:
    Mutex &_mutex;
    
public:
    LockGuard(Mutex &mutex) : _mutex(mutex) {
        _mutex.Lock();
    }
    ~LockGuard() {
        _mutex.Unlock();
    }
};

五、Log.hpp - 日志系统

5.1 策略模式设计

复制代码
LogStrategy(抽象基类)
    ├── ConsoleLogStrategy(控制台输出)
    └── FileLogStrategy(文件输出)

5.2 日志等级

复制代码
enum class LogLevel {
    DEBUG,      // 调试信息
    INFO,       // 一般信息
    WARNING,    // 警告
    ERROR,      // 错误
    FATAL       // 致命错误
};

5.3 日志策略实现

5.3.1 控制台策略
复制代码
class ConsoleLogStrategy : public LogStrategy {
public:
    void SyncLog(const std::string &message) override {
        LockGuard lockguard(_mutex);
        std::cout << message << "\r\n";
    }
private:
    Mutex _mutex;  // 线程安全
};
5.3.2 文件策略
复制代码
class FileLogStrategy : public LogStrategy {
public:
    FileLogStrategy(const std::string &path = "./log", 
                    const std::string &file = "my.log") 
        : _path(path), _file(file) {
        // 自动创建目录
        if (!std::filesystem::exists(_path)) {
            std::filesystem::create_directories(_path);
        }
    }
    
    void SyncLog(const std::string &message) override {
        LockGuard lockguard(_mutex);
        std::string filename = _path + (_path.back() == '/' ? "" : "/") + _file;
        std::ofstream out(filename, std::ios::app);  // 追加模式
        out << message << "\r\n";
        out.close();
    }
};

5.4 日志格式

复制代码
[时间戳] [日志级别] [进程ID] [源文件名] [行号] - 日志内容
示例:
[2024-01-01 12:00:00] [INFO] [1234] [server.cpp] [45] - Socket created successfully

5.5 日志生成器

复制代码
class Logger {
private:
    std::unique_ptr<LogStrategy> _fflush_strategy;
    
    // 内部消息类(用于<<操作符)
    class LogMessage {
    public:
        template <typename T>
        LogMessage &operator<<(const T &info) {
            std::stringstream ss;
            ss << info;
            _loginfo += ss.str();
            return *this;
        }
        ~LogMessage() {
            // 析构时自动刷新
            _logger._fflush_strategy->SyncLog(_loginfo);
        }
    };
};

5.6 使用宏

复制代码
#define LOG(level) logger(level, __FILE__, __LINE__)
#define Enable_Console_Log_Strategy() logger.EnableConsoleLogStrategy()
#define Enable_File_Log_Strategy() logger.EnableFileLogStrategy()

// 使用示例
LOG(LogLevel::INFO) << "Server started on port " << port;

六、Socket.hpp - Socket封装

6.1 模版方法模式

复制代码
class Socket {  // 抽象基类
public:
    virtual ~Socket() {}
    virtual void SocketOrDie() = 0;
    virtual void BindOrDie(uint16_t port) = 0;
    virtual void ListenOrDie(int backlog) = 0;
    virtual std::shared_ptr<Socket> Accept(InetAddr *client) = 0;
    virtual void Close() = 0;
    
    // 模版方法:构建TCP Socket的标准流程
    void BuildTcpSocketMethod(uint16_t port, int backlog = 16) {
        SocketOrDie();      // 1. 创建socket
        BindOrDie(port);    // 2. 绑定地址
        ListenOrDie(backlog); // 3. 开始监听
    }
};

6.2 TCP Socket实现

复制代码
class TcpSocket : public Socket {
private:
    int _sockfd;  // 套接字描述符
    
public:
    TcpSocket() : _sockfd(-1) {}
    TcpSocket(int fd) : _sockfd(fd) {}  // 用于accept返回的已连接socket
    
    void SocketOrDie() override {
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0) {
            LOG(LogLevel::FATAL) << "socket error";
            exit(SOCKET_ERR);
        }
    }
    
    void BindOrDie(uint16_t port) override {
        InetAddr localaddr(port);
        int n = ::bind(_sockfd, localaddr.NetAddrPtr(), localaddr.NetAddrLen());
        if (n < 0) {
            LOG(LogLevel::FATAL) << "bind error";
            exit(BIND_ERR);
        }
    }
    
    void ListenOrDie(int backlog) override {
        int n = ::listen(_sockfd, backlog);
        if (n < 0) {
            LOG(LogLevel::FATAL) << "listen error";
            exit(LISTEN_ERR);
        }
    }
    
    std::shared_ptr<Socket> Accept(InetAddr *client) override {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int fd = ::accept(_sockfd, CONV(peer), &len);
        if (fd < 0) {
            LOG(LogLevel::WARNING) << "accept warning ...";
            return nullptr;
        }
        client->SetAddr(peer);  // 设置客户端地址
        return std::make_shared<TcpSocket>(fd);  // 返回已连接的socket
    }
    
    void Close() {
        if (_sockfd >= 0)
            ::close(_sockfd);
    }
};

七、设计模式总结

7.1 策略模式(日志系统)

  • 抽象策略 : LogStrategy定义日志输出接口

  • 具体策略 : ConsoleLogStrategyFileLogStrategy实现不同输出方式

  • 上下文 : Logger类使用策略对象

7.2 模版方法模式(Socket)

  • 抽象类 : Socket定义算法骨架

  • 具体实现 : TcpSocket实现具体步骤

  • 固定流程 : BuildTcpSocketMethod()封装标准TCP服务端创建流程

7.3 RAII模式(资源管理)

  • 互斥锁 : LockGuard在构造时加锁,析构时自动解锁

  • 日志消息 : LogMessage在析构时自动刷新日志

八、使用示例

8.1 创建TCP服务器

复制代码
#include "Socket.hpp"
#include "Log.hpp"

int main() {
    using namespace SocketModule;
    using namespace LogModule;
    
    Enable_Console_Log_Strategy();
    
    TcpSocket server;
    server.BuildTcpSocketMethod(8080, 10);
    
    while (true) {
        InetAddr clientAddr;
        auto clientSocket = server.Accept(&clientAddr);
        if (clientSocket) {
            LOG(LogLevel::INFO) << "New connection from: " 
                               << clientAddr.StringAddr();
            // 处理连接...
        }
    }
    
    return 0;
}

8.2 日志使用示例

复制代码
LOG(LogLevel::INFO) << "Server started";
LOG(LogLevel::DEBUG) << "Processing request: " << request_id;
LOG(LogLevel::ERROR) << "Failed to process: " << error_msg;

九、关键特性

  1. 类型安全: 使用C++类和模板,避免原始指针

  2. 异常安全: RAII管理资源,防止泄露

  3. 线程安全: 日志系统内部使用互斥锁

  4. 可扩展性: 策略模式便于添加新的日志输出方式

  5. 易用性: 宏定义简化日志记录

  6. 错误处理: 统一错误码和日志记录

十、注意事项

  1. 跨平台限制: 使用了POSIX API,主要适用于Linux/Unix

  2. 内存管理: 使用智能指针自动管理资源

  3. 性能考虑: 日志输出在析构时进行,注意作用域

  4. 配置灵活性: 日志策略可在运行时切换

  5. 错误处理: 致命错误直接退出,适合简单应用

相关推荐
安科士andxe6 小时前
深入解析|安科士1.25G CWDM SFP光模块核心技术,破解中长距离传输痛点
服务器·网络·5g
mCell7 小时前
如何零成本搭建个人站点
前端·程序员·github
mCell8 小时前
为什么 Memo Code 先做 CLI:以及终端输入框到底有多难搞
前端·设计模式·agent
恋猫de小郭8 小时前
AI 在提高你工作效率的同时,也一直在增加你的疲惫和焦虑
前端·人工智能·ai编程
少云清8 小时前
【安全测试】2_客户端脚本安全测试 _XSS和CSRF
前端·xss·csrf
YJlio8 小时前
1.7 通过 Sysinternals Live 在线运行工具:不下载也能用的“云端工具箱”
c语言·网络·python·数码相机·ios·django·iphone
银烛木8 小时前
黑马程序员前端h5+css3
前端·css·css3
m0_607076608 小时前
CSS3 转换,快手前端面试经验,隔壁都馋哭了
前端·面试·css3
听海边涛声8 小时前
CSS3 图片模糊处理
前端·css·css3
IT、木易8 小时前
css3 backdrop-filter 在移动端 Safari 上导致渲染性能急剧下降的优化方案有哪些?
前端·css3·safari