linux下tcp/udp协议网络通信接口封装+日志打印对象

发布于:2024-04-27 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

引入

代码

log.hpp代码


引入

我们可以把之前写过的代码拿过来整合一下,直接封装出网络套接字的接口

  • 这样之后再使用的话,直接调用接口即可
  • 这里写的是tcp协议,也可以修改socket函数里的参数,改为udp协议

代码

#pragma once
 
#include <iostream>
#include <string>
 
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
 
#include "Log.hpp"
 
enum
{
    SOCK_ERROR = 2,
    BIND_ERROR,
    LISTEN_ERROR
};
 
int def_log = 10;
 
// 封装出socket接口
class MY_SOCKET
{
public:
    MY_SOCKET()
        : sockfd_(0)
    {
    }
    ~MY_SOCKET()
    {
        Close();
    }
    void Socket()
    {
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            lg(FATAL, "socket create error, sockfd : %d,%s", sockfd_, strerror(errno));
            exit(SOCK_ERROR);
        }
        lg(INFO, "socket create success, sockfd : %d", sockfd_);
    }
    void Bind(int port)
    {
        struct sockaddr_in *addr = new sockaddr_in;
        memset(addr, 0, sizeof(*addr));
        addr->sin_family = AF_INET;
        addr->sin_addr.s_addr = INADDR_ANY; // 接收任何主机发来的数据包
        addr->sin_port = htons(port);
 
        int t = bind(sockfd_, reinterpret_cast<struct sockaddr *>(addr), sizeof(*addr));
        if (t < 0)
        {
            lg(FATAL, "bind error, sockfd : %d,%s", sockfd_, strerror(errno));
            exit(BIND_ERROR);
        }
        lg(INFO, "bind success, sockfd : %d", sockfd_);
    }
    void Listen()
    {
        if (listen(sockfd_, def_log) < 0)
        {
            lg(FATAL, "listen error, sockfd : %d,%s", sockfd_, strerror(errno));
            exit(LISTEN_ERROR);
        }
        lg(INFO, "listen success, sockfd : %d", sockfd_);
    }
    int Accept(std::string &clientip, uint16_t &clientport)
    {
        sockaddr_in client_addr;
        socklen_t client_len = sizeof(client_addr);
        memset(&client_addr, 0, client_len);
 
        int sockfd = accept(sockfd_, reinterpret_cast<struct sockaddr *>(&client_addr), &client_len);
        if (sockfd < 0)
        {
            lg(WARNING, "accept error, %s: %d", strerror(errno), errno);
            return -1;
        }
        char client_ip[32];
        inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, sizeof(client_ip));
        clientip = client_ip;
        clientport = ntohs(client_addr.sin_port);
 
        return sockfd;
    }
    bool Connect(const std::string &ip, const uint16_t &port)
    {
        struct sockaddr_in *server_addr = new sockaddr_in;
        memset(server_addr, 0, sizeof(*server_addr));
 
        server_addr->sin_family = AF_INET;
        inet_pton(AF_INET, ip.c_str(), &(server_addr->sin_addr));
        server_addr->sin_port = htons(port);
 
        int ret = connect(sockfd_, reinterpret_cast<struct sockaddr *>(server_addr), sizeof(*server_addr));
        if (ret < 0)
        {
            printf("connect fail : %s:%d\n", ip.c_str(), port);
            return false;
        }
        //printf("connect success\n");
        return true;
    }
    void Close() // tcp协议在初始化好后,就不需要这个套接字了(子进程)
    {
        close(sockfd_);
    }
    int get_fd()
    {
        return sockfd_;
    }
 
public:
    int sockfd_;
};

log.hpp代码

里面用到的lg其实是我们自定义的日志对象

  • 既可以在屏幕上打印,也可以将输出重定向到指定路径的文件里

代码如下:

#pragma once

#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#define INFO 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4 // 致命的错误

#define SCREEN 1
#define ONEFILE 2

#define DEF_NAME "log.txt"
#define DEF_PATH "./log/"

#define SIZE 1024

class Log
{
public:
    Log()
        : method_(SCREEN), path_(DEF_PATH)
    {
    }
    void enable()
    {
        method_ = ONEFILE;
    }
    void operator()(int level, const char *format, ...)
    {
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);

        char leftbuffer[SIZE];
        snprintf(leftbuffer, sizeof(leftbuffer), "[%s][%d-%d-%d %d:%d:%d]", levelToString(level).c_str(),
                 ctime->tm_year + 1900, ctime->tm_mon + 1, ctime->tm_mday,
                 ctime->tm_hour, ctime->tm_min, ctime->tm_sec);

        va_list s;
        va_start(s, format);
        char rightbuffer[SIZE];
        vsnprintf(rightbuffer, sizeof(rightbuffer), format, s);
        va_end(s);

        // 格式:默认部分+自定义部分
        char logtxt[SIZE * 2];
        snprintf(logtxt, sizeof(logtxt), "%s %s\n", leftbuffer, rightbuffer);

        printLog(logtxt);
    }
    ~Log()
    {
    }

private:
    std::string levelToString(int level)
    {
        switch (level)
        {
        case INFO:
            return "INFO";
        case DEBUG:
            return "DEBUG";
        case WARNING:
            return "WARNING";
        case ERROR:
            return "ERROR";
        case FATAL:
            return "FATAL";
        default:
            return "NONE";
        }
    }
    void printLog(const std::string &logtxt)
    {
        switch (method_)
        {
        case SCREEN:
            std::cout << logtxt;
            break;
        case ONEFILE:
            printOneFile(logtxt);
            break;
        default:
            break;
        }
    }
    void printOneFile(const std::string &info)
    {
        std::string path = path_ + DEF_NAME;
        int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd > 0)
        {
            write(fd, info.c_str(), info.size());
            close(fd);
        }
        else
        {
            return;
        }
    }

private:
    int method_;
    std::string path_;
};

Log lg;


网站公告

今日签到

点亮在社区的每一天
去签到