muduo/net库(1)

1 如果说你不用muduo的net库,让你用epoll监听,你会怎样写服务器?

下面是我写的,为了让代码的逻辑更加清晰,我这里没有进行出错判断。
这只是一个简单的回射服务器

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <vector>
#include <sys/epoll.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>

#include <stdlib.h>

using namespace std;

#define SERVPORT 8888
#define SERVIP INADDR_ANY


//使用epoll进行监听
//为了使得代码更加简洁,这里就不进行出错判断

typedef std::vector<struct epoll_event> EventList;

int main()
{
    //忽略两个SIGPIPE和SIGCHLD信号
    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);

    int conn;
    struct sockaddr_in clieaddr;
    socklen_t clieaddr_len = sizeof(clieaddr);

    //首先创建一个套接字
    int listenfd;
    listenfd = socket(AF_INET,SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC,0);

     //设置端口复用
    int opt = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));


    //绑定端口和ip
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htobe16(SERVPORT);
    servaddr.sin_addr.s_addr = htobe32(SERVIP);
    bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

    //设置监听上限
    listen(listenfd,SOMAXCONN);

    //创建一个epoll
    int epollfd;
    epollfd = epoll_create1(EPOLL_CLOEXEC);

    //将套接字加入到epoll监听中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listenfd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&event);

    //这是发生事件的个数
    int nready;

    EventList events(16);

    //存放ip的地方
    char ip[32];
    //循环进行监听
    while(1){
        nready = epoll_wait(epollfd,&*events.begin(),static_cast<int>(events.size()),-1);
        if(nready == -1){
            perror("epoll_wait");
            exit(-1);
        }



        if(nready == 0){
            continue;
        }
        if(((size_t)nready == events.size())){
            events.resize(events.size()*2);
        }

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

            //判断监听到的事件
            //如果是创建链接的套接字有事件发生
            if(events[i].data.fd == listenfd){
                //定义的客户端的套接字用来接收链接服务器的套接字
                conn = accept4(listenfd,(struct sockaddr*)&clieaddr,&clieaddr_len,SOCK_NONBLOCK|SOCK_CLOEXEC);
                 cout<<"ip:"<< inet_ntop(AF_INET,&clieaddr.sin_addr,ip,sizeof(ip))<< "  port:"
                 <<ntohs(clieaddr.sin_port)<<endl;
                //打印客户端的ip和端口号
                //cout<<"ip:"<<inet_ntop(AF_INET,&clieaddr.sin_addr.s_addr,ip,sizeof(ip))<< " ";
                //cout<<"port:"<<ntohs(clieaddr.sin_port);

                event.events = EPOLLIN;
                event.data.fd = conn;
                epoll_ctl(epollfd,EPOLL_CTL_ADD,conn,&event);
                clients.push_back(conn);

            }
            //如果是客户端的套接字有事件发生
            else if(events[i].events & EPOLLIN){
                conn = events[i].data.fd;
                //读取套接字里面的内容

                char buf[1024] = {0};
                int ret = read(conn,buf,sizeof(buf));
                cout<<ret<<endl;
                if(ret == 0){
                    epoll_ctl(epollfd,EPOLL_CTL_DEL,conn,&events[i]);
                }
                //对内容进行处理之后,将处理后的内容写入到客户端的套接字中
                write(conn,buf,ret);
            }

        }
    }


    cout << "Hello world!" << endl;
    return 0;
}

2 如果将循环的那部分都放在一个类中来实现

这个类就是Eventloop类

简单的设计eventloop类
其中EventLoop.h

#ifndef EVENTLOOP_H
#define EVENTLOOP_H

#include <sys/epoll.h>
#include <netinet/in.h>
#include <vector>
#include <stdio.h>
#include <error.h>
#include <stdlib.h>
#include <iostream>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

using namespace std;

typedef std::vector<struct epoll_event> EventList;


class EventLoop
{
    public:
        EventLoop();
        ~EventLoop();

        //有一个设置epollfd_的函数
        void setEpollfd(int epollfd);
        //有一个设置listenfd的函数
        void setListenfd(int listenfd);

        //有一个事件循环函数
        void loop();

        //有一个退出循环的函数
        void quit();

    protected:

    private:
        bool looping_;  //是否处于循环中
        bool quit_;  //是否退出循环

        //事件循环中的epollfd和listenfd
        int epollfd_;
        int listenfd_;
};

#endif // EVENTLOOP_H

EventLoop.cpp

#include "EventLoop.h"

EventLoop::EventLoop()
{
    //ctor
    looping_ = false;
    quit_ = false;
}

EventLoop::~EventLoop()
{
    //dtor
}


//有一个设置epollfd_的函数
void EventLoop::setEpollfd(int epollfd)
{
    epollfd_ = epollfd;
}
//有一个设置listenfd的函数
void EventLoop::setListenfd(int listenfd)
{
    listenfd_ = listenfd;
}

//有一个事件循环函数
void EventLoop::loop()
{

    /*
    这里面,目前必须要的是,
        1.服务器的监听套接字  listenfd_
        2.epoll监听的epollfd  epollfd_
        3.用来接受epoll监听事件返回的数组
        4.客户端的套接字,和客户端的socket地址的定义
        5.一个event用来接受客户端的套接字和需要监听的事件

    */
    looping_ = true;

    //3.用来接受epoll监听事件返回的数组
    //接受epoll监听返回的数组
    EventList events(16);

    //客户端的一些链接信息
    //4.客户端的套接字,和客户端的socket地址的定义
    int conn;
    struct sockaddr_in clieaddr;
    socklen_t clieaddr_len = sizeof(clieaddr);

    //5.一个event用来接受客户端的套接字和需要监听的事件
    struct epoll_event event;

     //这是发生事件的个数
    int nready;

    //存放ip的地方
    char ip[32];
    //循环进行监听
    while(!quit_){
        nready = epoll_wait(epollfd_,&*events.begin(),static_cast<int>(events.size()),-1);
        if(nready == -1){
            perror("epoll_wait");
            exit(-1);
        }



        if(nready == 0){
            continue;
        }
        if(((size_t)nready == events.size())){
            events.resize(events.size()*2);
        }

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

            //判断监听到的事件
            //如果是创建链接的套接字有事件发生
            if(events[i].data.fd == listenfd_){
                //定义的客户端的套接字用来接收链接服务器的套接字
                conn = accept4(listenfd_,(struct sockaddr*)&clieaddr,&clieaddr_len,SOCK_NONBLOCK|SOCK_CLOEXEC);
                //打印客户端的ip和端口号
                 cout<<"ip:"<< inet_ntop(AF_INET,&clieaddr.sin_addr,ip,sizeof(ip))<< "  port:"
                 <<ntohs(clieaddr.sin_port)<<endl;


                event.events = EPOLLIN;
                event.data.fd = conn;
                epoll_ctl(epollfd_,EPOLL_CTL_ADD,conn,&event);


            }
            //如果是客户端的套接字有事件发生
            else if(events[i].events & EPOLLIN){
                conn = events[i].data.fd;
                //读取套接字里面的内容

                char buf[1024] = {0};
                int ret = read(conn,buf,sizeof(buf));
                cout<<ret<<endl;
                if(ret == 0){
                    epoll_ctl(epollfd_,EPOLL_CTL_DEL,conn,&events[i]);
                }
                //对内容进行处理之后,将处理后的内容写入到客户端的套接字中
                write(conn,buf,ret);
            }

        }
    } //while循环结束


}

//有一个退出循环的函数
void EventLoop::quit()
{
    quit_ = true;
}

main.cpp

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <vector>
#include <sys/epoll.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>

#include <stdlib.h>

#include <EventLoop.h>

using namespace std;

#define SERVPORT 8888
#define SERVIP INADDR_ANY


//使用epoll进行监听
//为了使得代码更加简洁,这里就不进行出错判断



int main()
{
    //忽略两个SIGPIPE和SIGCHLD信号
    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);

    //首先创建一个套接字
    int listenfd;
    listenfd = socket(AF_INET,SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC,0);

     //设置端口复用
    int opt = 1;
    setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));


    //绑定端口和ip
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htobe16(SERVPORT);
    servaddr.sin_addr.s_addr = htobe32(SERVIP);
    bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

    //设置监听上限
    listen(listenfd,SOMAXCONN);

    //创建一个epoll
    int epollfd;
    epollfd = epoll_create1(EPOLL_CLOEXEC);

    //将套接字加入到epoll监听中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listenfd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&event);

    EventLoop eloop;
    eloop.setEpollfd(epollfd);
    eloop.setListenfd(listenfd);
    eloop.loop();



    return 0;
}

3. 将listenfd的设置端口复用,绑定,监听又都封装成一个Socket类

Socket.h

#ifndef SOCKET_H
#define SOCKET_H


#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>


//listenfd的绑定,监听过程在这个类中来实现
class Socket
{
    public:
        explicit Socket(int sockfd);
        ~Socket();

        //套接字的ip和端口绑定函数
        void bindAddress();

        //套接字的监听函数
        void listenfd();

        //设置套接字端口复用函数
        void setReuseAddr(bool on);

        //返回套接字的fd
        int fd();



    protected:

    private:
        const int sockfd_;
};

#endif // SOCKET_H

Socket.cpp

#include "Socket.h"

#define SERVPORT 8888
#define SERVIP INADDR_ANY

Socket::Socket(int sockfd)
:sockfd_(sockfd)
{
    //ctor
}

Socket::~Socket()
{
    //dtor
}


//套接字的ip和端口绑定函数
void Socket::bindAddress()
{
    //绑定端口和ip
    struct sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htobe16(SERVPORT);
    servaddr.sin_addr.s_addr = htobe32(SERVIP);
    bind(sockfd_,(struct sockaddr*)&servaddr,sizeof(servaddr));

}

//套接字的监听函数
void Socket::listenfd()
{
    listen(sockfd_,SOMAXCONN);
}

//设置套接字端口复用函数
void Socket::setReuseAddr(bool on)
{
    int opt = on? 1:0;
    setsockopt(sockfd_,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
}

//返回套接字的fd
int Socket::fd()
{
    return sockfd_;
}


main.cpp

#include <iostream>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <vector>
#include <sys/epoll.h>
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>

#include <stdlib.h>

#include <EventLoop.h>
#include <Socket.h>

using namespace std;




//使用epoll进行监听
//为了使得代码更加简洁,这里就不进行出错判断



int main()
{
    //忽略两个SIGPIPE和SIGCHLD信号
    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);

    //首先创建一个套接字
    int listenfd;
    listenfd = socket(AF_INET,SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC,0);

    Socket socket(listenfd);
    socket.setReuseAddr(true);
    socket.bindAddress();
    socket.listenfd();

    listenfd = socket.fd();

    //创建一个epoll
    int epollfd;
    epollfd = epoll_create1(EPOLL_CLOEXEC);

    //将套接字加入到epoll监听中
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = listenfd;
    epoll_ctl(epollfd,EPOLL_CTL_ADD,listenfd,&event);

    EventLoop eloop;
    eloop.setEpollfd(epollfd);
    eloop.setListenfd(listenfd);
    eloop.loop();



    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值