程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 仿MoDuo封裝簡易C++網絡庫

仿MoDuo封裝簡易C++網絡庫

編輯:關於C++

整體架構:

主要有這麼幾個類:
Server, Epoll, Socket, Accept, User.

初版代碼,i/o處理不完善,僅供參考,主要是結構
還有部分功能沒有實現,以後陸續加需求。

這裡寫圖片描述

1.Accept類

第一層:Accept類,主要處理客戶端連接,為上層提供與該客戶端通信的套接字描述符

class FDB_Accept {

public:

    FDB_Accept() = default;
    FDB_Accept(int request_fd);
    ~FDB_Accept();
    int getAccepted_fd();
/*  int Accept_write(char * str);
    int Accept_read (char * str);
*/
private:

    int m_iAccepted_fd;
    struct sockaddr_in m_Client_addr;
    socklen_t m_cli_AddrLength = sizeof(m_Client_addr);

    /*int m_iSock_fd;*/
    /*char connfd_buf[100];*/
    /*Buffer connfd_buf;*/
    /*int id;*/

};
#include "FDB_Accept.h"


FDB_Accept::FDB_Accept(int request_fd) {

/*    m_iSock_fd = request_fd;*/
    m_iAccepted_fd = accept(request_fd, (struct sockaddr*)&m_Client_addr, &m_cli_AddrLength);

    if(  -1 == m_iAccepted_fd)
        std::cout << "accept ERROR!" << std::endl;

}


int FDB_Accept::getAccepted_fd() {

    return m_iAccepted_fd;
}

FDB_Accept::~FDB_Accept() {

}



2.User類

維護一個在線用戶數組,主要為了管理與服務器建立連接的客戶端。為上層提供添加,查找,刪除,查看用戶信息等功能。

#ifndef MY_NETLIB_USER_H
#define MY_NETLIB_USER_H

#include 
#include 
#include "FDB_Accept.h"

class FDB_Users {

public:

    FDB_Users();
    ~FDB_Users() = default;

    void User_add(FDB_Accept rhs);

    bool User_del(int rhs_fd);
    bool User_mod();
    bool User_find(int rhs_fd);
    bool User_show();

    FDB_Accept get_Accepter(int rhs_fd);


private:

    std::vector  m_vct_Acpt_User_data;

};


#endif //MY_NETLIB_USER_H
#include "FDB_Users.h"

FDB_Users::FDB_Users(){

}


void FDB_Users::User_add(FDB_Accept rhs) {
    m_vct_Acpt_User_data.push_back(rhs);
}


bool FDB_Users::User_del(int rhs_fd) {

    for(auto item = m_vct_Acpt_User_data.begin(); item != m_vct_Acpt_User_data.end(); item++)
    {
        if((*item).getAccepted_fd() == rhs_fd) {
            m_vct_Acpt_User_data.erase(item);
            return true;
        }
    }

    return false;
}


bool FDB_Users::User_mod() {

}


bool FDB_Users::User_find(int rhs_fd) {

    int size = 0;
    for(auto item : m_vct_Acpt_User_data){

        size++;
        if(rhs_fd == item.getAccepted_fd())
            return true;
    }
    std::cout << size << std::endl;
    return false;
}


bool FDB_Users::User_show() {

    for(auto item:m_vct_Acpt_User_data)
        std::cout << "On line user acpted_fd: " <

3.Socket類

主要用於服務端各種初始化,創建套接字,綁定監聽,並設置非阻塞。 為上層提供用於監聽的套接字描述符

class FDB_Socket {

public:

    explicit FDB_Socket(int sockfd):m_iSockfd(sockfd){};                       /*聲明為explicit的構造函數不能在隱式轉換中使用。,如果存在直接賦值*/

    FDB_Socket(sa_family_t family, int listen_num);
    ~FDB_Socket();

    bool Socket_createSocket(sa_family_t family = AF_INET, int backlog = 100);             /*構造核心函數*/
    bool Socket_bindAddress();                                                  /*命名套接字*/
    bool Socket_listen(int backlog);                                            /*監聽套接字*/
    bool Socket_setReusePort(bool on);                                          /*設置端口重用*/
    bool Socket_setTimeOutRecnt(bool on);                                       /*設置超時重連*/
    int  Socket_setNoBlocking();                                                /*設置 m_iSockfd 為非阻塞*/
    int  Socket_getfd();                                                        /*獲取套接字描述符 m_iSockfd*/

    int  Socket_do_accept();
    bool Socket_getbacklog();
    bool Socket_shutdownWrite();
    bool Socket_TcpNoDelay(bool on);
    bool Socket_setResuseAddr(bool on);
    bool Socket_setKeepAlive(bool on);
    bool test_accept();
/*
    bool Socket_getTcpInfo(struct tcp_info *) const;
    bool Socket_getTcpInfoString(char * buf, int len) const;
*/
private:

    int m_iSockfd;
    int m_iBacklog;
    struct sockaddr_in m_addr_inAddress;
    struct sockaddr_in m_addr_inCliaddr;

};
#include "FDB_Socket.h"
typedef struct sockaddr SA;

/***************************核心構造函數***********************************************/
FDB_Socket::FDB_Socket(sa_family_t family, int listen_num) {

    Socket_createSocket(family, listen_num);

    Socket_setReusePort(true);
    bzero(&m_addr_inAddress, sizeof(m_addr_inAddress));

    m_addr_inAddress.sin_family      = AF_INET;                                             /*協議族*/
    m_addr_inAddress.sin_addr.s_addr = htonl(INADDR_ANY);                                   /*ip*/
    m_addr_inAddress.sin_port        = htons(9201);                                         /*port*/

    if(Socket_bindAddress() && (m_iSockfd > 0)) {                                           /*綁定*/

        if(Socket_listen(listen_num)) {                                                     /*監聽*/

            if(Socket_setNoBlocking())                                                      /*非阻塞*/
                return;
        }
    }
}

bool FDB_Socket::Socket_createSocket(sa_family_t family, int listen_num) {                            /*創建一個socket*/

    m_iBacklog = listen_num;
    m_iSockfd =  socket(family, SOCK_STREAM, 0);                                            /*調用socket(),創建一個socket*/


    if( m_iSockfd < 0)
        std::cout << "log_net_error" << std::endl;                                          /*創建socket失敗*/

}


bool FDB_Socket::Socket_bindAddress() {

    std::cout << "m_iSockfd = " << m_iSockfd << "  len = " << sizeof(m_addr_inAddress) << std::endl;

    int ret = bind(m_iSockfd, (SA*)&m_addr_inAddress, sizeof(m_addr_inAddress));            /*命名m_iSocket*/

    if(ret < 0){
        std::cout << "bind ERROR!   return " << ret << std::endl;                           /*命名失敗*/
        return false;
    }

    return true;

}

bool FDB_Socket::Socket_listen(int backlog) {

    int ret = listen(m_iSockfd, backlog);                                                   /*監聽套接字m_iSockfd*/

    if(ret < 0) {
        std::cout << "listen ERROR" < 0) {
            if(fork() == 0)
            {
                char buf[100];
                while(read(connfd, buf, 100) > 0) {
                    std::cout << buf << std::endl;
                }
            }
        }

    }
}
bool FDB_Socket::Socket_getbacklog(){}
bool FDB_Socket::Socket_shutdownWrite(){}
bool FDB_Socket::Socket_TcpNoDelay(bool on){}



bool FDB_Socket::Socket_setReusePort(bool on) {                                                     /*設置端口重用*/

    int optval = on ? 0 : 1;
    ::setsockopt(m_iSockfd, SOL_SOCKET, SO_REUSEPORT, &optval, static_cast(sizeof optval));

    return true;

}

bool FDB_Socket::Socket_setResuseAddr(bool on) {                                                    /*設置地址重用*/

    int optval = on ? 1: 0;
    ::setsockopt(m_iSockfd, SOL_SOCKET, SO_REUSEADDR, &optval, static_cast(sizeof optval));

    return true;

}


bool FDB_Socket::Socket_setTimeOutRecnt(bool on){

    int optval = on ? 1: 0;
    ::setsockopt(m_iSockfd, SOL_SOCKET, SO_SNDTIMEO, &optval, static_cast(sizeof optval));
}


int  FDB_Socket::Socket_setNoBlocking() {                   /*設置 m_iSockfd 為非阻塞*/

    int old_option = fcntl(m_iSockfd,F_GETFL);
    int new_option = old_option | O_NONBLOCK;
    fcntl(m_iSockfd , F_SETFL, new_option);
    return old_option;
}

bool FDB_Socket::Socket_setKeepAlive(bool on) {             /*保持活著*/

    int optval = on ? 1 : 0;
    ::setsockopt(m_iSockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast(sizeof optval));
    return true;
}


bool FDB_Socket::test_accept(){

}

int  FDB_Socket::Socket_getfd(){                            /*獲取套接字描述符 m_iSockfd*/
    return m_iSockfd;
}

4.Epoll類

服務端核心類,主循環,監聽讀寫事件,做轉發

class FDB_Epoll {

public:

    FDB_Epoll(int fd);                                                  /*構造函數*/
   ~FDB_Epoll()      ;                                                  /*析構函數*/

    bool Epoll_create_events();                                         /*創建epoll_event*/
    bool Epoll_reset(int fd);                                           /*重置epoll_fd*/
    bool Epoll_add(int fd, bool enable_et, bool oneshot);               /*添加可讀事件*/
    bool Epoll_add_initListen(int fd, bool enable_et);                      /*添加監聽事件*/
    bool Epoll_setnoblocking(int socket_fd);                            /*設置非阻塞*/
    bool Epoll_del(int fd);                                             /*刪除epoll事件*/
    bool Epoll_wait();                                                  /*核心函數*/

private:

    int m_iEpoll_fd             ;
    const int m_ciMAX_NUM = 100 ;
    int m_iBUF_SIZE             ;
    int m_iListen_fd            ;
    int m_iDBfd                 ;
    epoll_event * m_epEvent_p   ;

};
#include "FDB_Epoll.h"
#include "FDB_Accept.h"
#include "FDB_Users.h"
#include "FDB_Users.h"
#include 

//extern FDB_Users user;
FDB_Users user;

FDB_Epoll::FDB_Epoll(int fd) {                                              /*構造函數*/

    m_iListen_fd = fd;                                                      /*初始化m_iSock_fd*/
    m_iEpoll_fd = epoll_create(m_ciMAX_NUM);                                /*創建epoll實例*/
    Epoll_create_events();                                                  /*開辟epoll_event空間*/

    if( -1 == m_iEpoll_fd)
        std::cout << "epoll_create ERROR! "<< std::endl;

//測試用代碼
    const char * ip = "192.168.30.140";
    //int port = 6550;
    int port = 9201;

    struct sockaddr_in server_address2;
    bzero( &server_address2, sizeof(server_address2) );
    server_address2.sin_family = AF_INET;
    inet_pton( AF_INET, ip, &server_address2.sin_addr );
    server_address2.sin_port = htons(port);

    int DB_sockfd2 = socket( PF_INET, SOCK_STREAM, 0 );
    assert(DB_sockfd2 >= 0);


    if( connect(DB_sockfd2, (struct sockaddr*)&server_address2, sizeof(server_address2)) < 0 )
    {
        printf("connetcion failed\n");
        //close(DB_sockfd2);
        m_iDBfd = -1;
    }else {

        printf("connetc DB_SERVER SUCCESSED !\n");
        m_iDBfd = DB_sockfd2;
    }
}


bool FDB_Epoll::Epoll_create_events() {

    m_epEvent_p = new epoll_event[m_ciMAX_NUM];                            /*開辟epoll_event空間*/

    if( !m_epEvent_p ) {
        std::cout << "new error go to log now! " << std::endl;
        return false;
    }

    return true;

}



bool FDB_Epoll::Epoll_add_initListen(int fd, bool enable_et){

    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN;

    if(enable_et) {
        event.events |= EPOLLET;
        /*event.events |= EPOLLONESHOT;*/
    }
    Epoll_setnoblocking(fd);
    epoll_ctl(m_iEpoll_fd, EPOLL_CTL_ADD, fd, &event);                      /*向興趣列表裡添加監聽事件*/
    return true;

}


bool FDB_Epoll::Epoll_add(int fd, bool enable_et, bool oneshot) {

    std::cout << "one shot!" << std::endl;
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN;

    if( enable_et ) {
        event.events |= EPOLLET;                                            /*設置邊沿觸發*/
    }

    if(oneshot) {
        event.events |= EPOLLONESHOT;                                       /*只處理一次*/
    }

    epoll_ctl(m_iEpoll_fd, EPOLL_CTL_ADD, fd, &event);                      /*添加*/
    Epoll_setnoblocking(fd);

    return true;

}


bool FDB_Epoll::Epoll_setnoblocking(int fd) {

    int old_option = fcntl(fd, F_GETFL);
    int new_option = old_option | O_NONBLOCK;

    fcntl(fd, F_SETFL, new_option);                                         /*設置非阻塞*/
    return (bool)old_option;

}

bool FDB_Epoll::Epoll_reset(int fd) {

    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET | EPOLLONESHOT;
    epoll_ctl(m_iEpoll_fd, EPOLL_CTL_MOD, fd, &event);                      /*重置讀事件,邊沿觸發, 處理一次*/

}

bool FDB_Epoll::Epoll_del(int fd) {

    epoll_event event;
    event.data.fd = fd;
    epoll_ctl(m_iEpoll_fd, EPOLL_CTL_DEL, fd, &event);                      /*刪除*/
    close(fd);

}


bool FDB_Epoll::Epoll_wait() {                                              /*epoll_wait()服務器核心*/

    bool work_status = true;
    Epoll_add_initListen(m_iListen_fd, false);

    while(work_status)
    {
        std::cout << "Debug_message: Showing On Line List ! " << std::endl;

        user.User_show();


        std::cout << "Debug_message: epoll waiting" << std::endl;
        int ep_event_num = epoll_wait(m_iEpoll_fd, m_epEvent_p, m_ciMAX_NUM, -1); /*調用epoll_wait() 核心函數*/
        assert(ep_event_num >= 0);

        for(int ep_event_i = 0; ep_event_i < ep_event_num; ep_event_i++) {

            int now_skfd = m_epEvent_p[ep_event_i].data.fd;
            int accepted_fd;

            if( (  m_epEvent_p[ep_event_i].events & EPOLLERR) ||
                (  m_epEvent_p[ep_event_i].events & EPOLLHUP) ||
                (!(m_epEvent_p[ep_event_i].events & EPOLLIN )) ) {          /*error,掛起,斷開,並且沒有發生讀事件*/

                std::cout << "Debug_message: epoll Error!" << std::endl;
                Epoll_del(now_skfd);

                continue;

            }else if(now_skfd == m_iListen_fd &&
                    (m_epEvent_p[ep_event_i].events & EPOLLIN) ) {                                /*新用戶接入,分配資源,接受連接*/

                FDB_Accept connt(now_skfd);
                accepted_fd = connt.getAccepted_fd();
                user.User_add(connt);
                Epoll_add(accepted_fd, true, false);

                std::cout << "One New Client !" << std::endl;

            }else if (m_epEvent_p[ep_event_i].events & EPOLLOUT) {                      /*寫事件*/

                //send()



            }else if (m_epEvent_p[ep_event_i].events & EPOLLIN) {                       /*讀事件*/

/***********************************************測試代碼********************************************/

                char tmp_buf[100];
                memset(tmp_buf, 0, sizeof(tmp_buf));
                fflush(stdin);
                ssize_t recv_num = recv(now_skfd, tmp_buf, 100, 0);
                puts(tmp_buf);

                if(0 == recv_num) {                                                     /*客戶端掉線*/

                    user.User_del(now_skfd);
                    Epoll_del(now_skfd);
                    std::cout << "Lost A Client ! " << std::endl;


                }

                std::cout << "Debug_message: Got a pice of message " << recv_num << " bites ";
                std::cout << "from fd: " << now_skfd << " client " << std::endl;

                if(m_iDBfd != -1) {

                    for(int i = 0; i < 300860; i++)

                        send(m_iDBfd, tmp_buf, (size_t)recv_num, 0);

                }
                send(now_skfd, tmp_buf, (size_t)recv_num, 0);

                memset(tmp_buf, 0, sizeof(tmp_buf));

/************************************************測試代碼****************************************************/

            }

        }/*end for(int i = 0; i < ret; i++)*/

    }/*end while(work_status)*/

}


FDB_Epoll::~FDB_Epoll() {

    delete[] m_epEvent_p;
}

5.Server類

主要實現多線程,將Epoll,Socket封裝起來

#include 
#include "FDB_Epoll.h"
#include "FDB_Socket.h"
#include 

class FDB_Server {

public:

    FDB_Server(int status, int connfd_num, int pthread_num);
   ~FDB_Server();


    bool server_start();
    int  get_server_fd();

/*
    bool server_end();
    bool server_change(int status);
    int  server_get_status();
*/

private:

    int m_iServer_status;
    int m_iConnfd_num;
    int m_iChanges;
    int m_iSocketfd;
    int m_iServer_thread_num;
};

static void server_work(int fd);
#include "FDB_Server.h"


FDB_Server::FDB_Server(int status, int connfd_num, int pthread_num) {   /*構造服務器基礎信息*/

    m_iServer_status     = status;                                      /*服務器狀態*/
    m_iConnfd_num        = connfd_num;                                  /*最大鏈接個數,其實需要限定下*/
    m_iServer_thread_num = pthread_num;                                 /*可配置的PEUSEPORT 個數*/

}


bool FDB_Server::server_start() {

    FDB_Socket    db_Server(AF_INET, 10)  ;
    m_iSocketfd = db_Server.Socket_getfd();

    std::thread   threads[m_iServer_thread_num];                          /*可配置的服務器線程數*/

    for(int i = 0 ; i < m_iServer_thread_num; i++) {

        threads[i] = std::thread(server_work, m_iSocketfd);

    }

    for(int i = 0; i < m_iServer_thread_num; i++) {

        threads[i].join();
    }

}

static void server_work(int fd ) {

    FDB_Epoll epo(fd);
    epo.Epoll_wait() ;

}
int  FDB_Server::get_server_fd() {

    return  m_iSocketfd;
}

/*
bool FDB_Server::server_end();
bool FDB_Server::server_change(int status);
int  FDB_Server::server_get_status();
*/

FDB_Server::~FDB_Server(){

}

另附完整代碼:
https://github.com/Dulun/Summer2016/tree/master/my_netlib

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved