文章标题

利用libevent和多线程 实现多并发的服务器的设计。主进程监听连接的到来使用一个base,进行事件循环。每当 一个连接进来时,创建一个新的线程实现与客户端之间的通信,子线程建立一个base,进行事件循环

客户端(多线程):
主线程->连接描述符(socket_fd = connectServer(ip, port);)
-》创建子进程(init_read_event_thread(socket_fd);)
-》 pthread_create(&thread,NULL,init_read_event,(void*)sock);
-》创建base,并且建立事件循环(
void* init_read_event(void* arg)
->事件的回调函数

    -》写数据给服务端

服务器(多线程)(base): ( 主要是一个线程一个base)
主线程-》listen(fd, 10);
-》设置事件循环

         event_set(&listen_ev, fd, EV_READ|EV_PERSIST, on_accept, NULL);(等待连接的到来)
            -》得到连接描述符

子线程 (base):
     accept_new_thread(new_fd);


         pthread_create(&thread,NULL,process_in_new_thread_when_accepted,(void*)sock);

            -》process_in_new_thread_when_accepted(void* arg)

                ->设置事件循环

服务器端程序:

#include <iostream>
#include <sys/select.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <string.h>
#include <event.h>
#include <stdlib.h>
using namespace std;

#define SERVER_IP "127.0.0.1"
#define SERVER_PORT 9090
#define BUF_SIZE 1024

struct sock_ev_write{//用户写事件完成后的销毁,在on_write()中执行
    struct event* write_ev;
    char* buffer;
};
struct sock_ev {//用于读事件终止(socket断开)后的销毁
    struct event_base* base;//因为socket断掉后,读事件的loop要终止,所以要有base指针
    struct event* read_ev;
};

/**
 * 销毁写事件用到的结构体
 */
void destroy_sock_ev_write(struct sock_ev_write* sock_ev_write_struct){
    if(NULL != sock_ev_write_struct){
//        event_del(sock_ev_write_struct->write_ev);//因为写事件没用EV_PERSIST,故不用event_del
        if(NULL != sock_ev_write_struct->write_ev){
            free(sock_ev_write_struct->write_ev);
        }
        if(NULL != sock_ev_write_struct->buffer){
            delete[]sock_ev_write_struct->buffer;
        }
        free(sock_ev_write_struct);
    }
}


/**
 * 读事件结束后,用于销毁相应的资源
 */
void destroy_sock_ev(struct sock_ev* sock_ev_struct){
   if(NULL == sock_ev_struct){
        return;
    }

    event_del(sock_ev_struct->read_ev);
    event_base_loopexit(sock_ev_struct->base, NULL);//停止loop循环
    if(NULL != sock_ev_struct->read_ev){
        free(sock_ev_struct->read_ev);
    cout<<"free read_ev succeed"<<endl;
    }


/*    if(NULL !=sock_ev_struct->base)
    {
        event_base_free(sock_ev_struct->base);

        cout<<"free base succeed"<<endl;

    }*/
//    destroy_sock_ev_write(sock_ev_struct->sock_ev_write_struct);

    if(NULL !=sock_ev_struct)
    {
        free(sock_ev_struct);
        cout<<"free sock_ev_struct"<<endl;
    }

}

int getSocket(){
    int fd =socket( AF_INET, SOCK_STREAM, 0 );
    if(-1 == fd){
        cout<<"Error, fd is -1"<<endl;
    }
    return fd;
}

void on_write(int sock, short event, void* arg)
{
    cout<<"on_write() called, sock="<<sock<<endl;
    if(NULL == arg){
        cout<<"Error! void* arg is NULL in on_write()"<<endl;
        return;
    }
    struct sock_ev_write* sock_ev_write_struct = (struct sock_ev_write*)arg;

    char buffer[BUF_SIZE];
    sprintf(buffer, "fd=%d, received[%s]", sock, sock_ev_write_struct->buffer);
//    int write_num0 = write(sock, sock_ev_write_struct->buffer, strlen(sock_ev_write_struct->buffer));
//    int write_num = write(sock, sock_ev_write_struct->buffer, strlen(sock_ev_write_struct->buffer));
    int write_num = write(sock, buffer, strlen(buffer));
    destroy_sock_ev_write(sock_ev_write_struct);
    cout<<"on_write() finished, sock="<<sock<<endl;
}

void on_read(int sock, short event, void* arg)
{
    cout<<"on_read() called, sock="<<sock<<endl;
    if(NULL == arg){
        return;
    }
    struct sock_ev* event_struct = (struct sock_ev*) arg;//获取传进来的参数
    char* buffer = new char[BUF_SIZE];
    memset(buffer, 0, sizeof(char)*BUF_SIZE);
    //--本来应该用while一直循环,但由于用了libevent,只在可以读的时候才触发on_read(),故不必用while了
    int size = read(sock, buffer, BUF_SIZE);
    if(0 == size){//说明socket关闭
        cout<<"read size is 0 for socket:"<<sock<<endl;
        destroy_sock_ev(event_struct);
        close(sock);
        return;
    }
    struct sock_ev_write* sock_ev_write_struct = (struct sock_ev_write*)malloc(sizeof(struct sock_ev_write));
    sock_ev_write_struct->buffer = buffer;
    struct event* write_ev = (struct event*)malloc(sizeof(struct event));//发生写事件(也就是只要socket缓冲区可写)时,就将反馈数据通过socket写回客户端
    sock_ev_write_struct->write_ev = write_ev;
    event_set(write_ev, sock, EV_WRITE, on_write, sock_ev_write_struct);
    event_base_set(event_struct->base, write_ev);
    event_add(write_ev, NULL);
    cout<<"on_read() finished, sock="<<sock<<endl;
}


/**
 * main执行accept()得到新socket_fd的时候,执行这个方法
 * 创建一个新线程,在新线程里反馈给client收到的信息
 */
void* process_in_new_thread_when_accepted(void* arg){
    long long_fd = (long)arg;
    int fd = (int)long_fd;
    if(fd<0){
        cout<<"process_in_new_thread_when_accepted() quit!"<<endl;
        return 0;
    }
    //-------初始化base,写事件和读事件--------
    struct event_base* base = event_base_new();
    struct event* read_ev = (struct event*)malloc(sizeof(struct event));//发生读事件后,从socket中取出数据

    //-------将base,read_ev,write_ev封装到一个event_struct对象里,便于销毁---------
    struct sock_ev* event_struct = (struct sock_ev*)malloc(sizeof(struct sock_ev));
    event_struct->base = base;
    event_struct->read_ev = read_ev;
    //-----对读事件进行相应的设置------------
    event_set(read_ev, fd, EV_READ|EV_PERSIST, on_read, event_struct);
    event_base_set(base, read_ev);
    event_add(read_ev, NULL);
    //--------开始libevent的loop循环-----------
    event_base_dispatch(base);
    cout<<"event_base_dispatch() stopped for sock("<<fd<<")"<<" in process_in_new_thread_when_accepted()"<<endl;


    event_base_free(base);   //必须在此删除子线程的base
    return 0;
}

/**
 * 每当accept出一个新的socket_fd时,调用这个方法。
 * 创建一个新线程,在新线程里与client做交互
 */
void accept_new_thread(int sock){
    pthread_t thread;
    pthread_create(&thread,NULL,process_in_new_thread_when_accepted,(void*)sock);
    pthread_detach(thread);
}

/**
 * 每当有新连接连到server时,就通过libevent调用此函数。
 *    每个连接对应一个新线程
 */
void on_accept(int sock, short event, void* arg)
{
    struct sockaddr_in remote_addr;
    int sin_size=sizeof(struct sockaddr_in);
    int new_fd = accept(sock,  (struct sockaddr*) &remote_addr, (socklen_t*)&sin_size);
    if(new_fd < 0){
        cout<<"Accept error in on_accept()"<<endl;
        return;
    }
    cout<<"new_fd accepted is "<<new_fd<<endl;
    accept_new_thread(new_fd);
    cout<<"on_accept() finished for fd="<<new_fd<<endl;
}

int main(){
    int fd = getSocket();
    if(fd<0){
        cout<<"Error in main(), fd<0"<<endl;
    }
    cout<<"main() fd="<<fd<<endl;
    //----为服务器主线程绑定ip和port------------------------------
    struct sockaddr_in local_addr; //服务器端网络地址结构体
    memset(&local_addr,0,sizeof(local_addr)); //数据初始化--清零
    local_addr.sin_family=AF_INET; //设置为IP通信
    local_addr.sin_addr.s_addr=inet_addr(SERVER_IP);//服务器IP地址
    local_addr.sin_port=htons(SERVER_PORT); //服务器端口号
    int bind_result = bind(fd, (struct sockaddr*) &local_addr, sizeof(struct sockaddr));
    if(bind_result < 0){
        cout<<"Bind Error in main()"<<endl;
        return -1;
    }
    cout<<"bind_result="<<bind_result<<endl;
    listen(fd, 10);
    //-----设置libevent事件,每当socket出现可读事件,就调用on_accept()------------
    struct event_base* base = event_base_new();
    struct event listen_ev;
    event_set(&listen_ev, fd, EV_READ|EV_PERSIST, on_accept, NULL);
    event_base_set(base, &listen_ev);
    event_add(&listen_ev, NULL);
    event_base_dispatch(base);
    //------以下语句理论上是不会走到的---------------------------
    cout<<"event_base_dispatch() in main() finished"<<endl;
    //----销毁资源-------------
    event_del(&listen_ev);
    event_base_free(base);
    cout<<"main() finished"<<endl;
}

客户端程序:

#include <iostream>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <string.h>
#include <event.h>
using namespace std;

#define BUF_SIZE 1024

/**
 * 连接到server端,如果成功,返回fd,如果失败返回-1
 */
int connectServer(char* ip, int port){
    int fd = socket( AF_INET, SOCK_STREAM, 0 );
    cout<<"fd= "<<fd<<endl;
    if(-1 == fd){
        cout<<"Error, connectServer() quit"<<endl;
        return -1;
    }
    struct sockaddr_in remote_addr; //服务器端网络地址结构体
    memset(&remote_addr,0,sizeof(remote_addr)); //数据初始化--清零
    remote_addr.sin_family=AF_INET; //设置为IP通信
    remote_addr.sin_addr.s_addr=inet_addr(ip);//服务器IP地址
    remote_addr.sin_port=htons(port); //服务器端口号
    int con_result = connect(fd, (struct sockaddr*) &remote_addr, sizeof(struct sockaddr));
    if(con_result < 0){
        cout<<"Connect Error!"<<endl;
        close(fd);
        return -1;
    }
    cout<<"con_result="<<con_result<<endl;
    return fd;
}

void on_read(int sock, short event, void* arg)
{
    char* buffer = new char[BUF_SIZE];
    memset(buffer, 0, sizeof(char)*BUF_SIZE);
    //--本来应该用while一直循环,但由于用了libevent,只在可以读的时候才触发on_read(),故不必用while了
    int size = read(sock, buffer, BUF_SIZE);
    if(0 == size){//说明socket关闭
        cout<<"read size is 0 for socket:"<<sock<<endl;
        struct event* read_ev = (struct event*)arg;
        if(NULL != read_ev){
            event_del(read_ev);
            free(read_ev);
        }
        close(sock);
        return;
    }
    cout<<"Received from server---"<<buffer<<endl;
    delete[]buffer;
}

void* init_read_event(void* arg){
    long long_sock = (long)arg;
    int sock = (int)long_sock;
    //-----初始化libevent,设置回调函数on_read()------------
    struct event_base* base = event_base_new();
    struct event* read_ev = (struct event*)malloc(sizeof(struct event));//发生读事件后,从socket中取出数据
    event_set(read_ev, sock, EV_READ|EV_PERSIST, on_read, read_ev);
    event_base_set(base, read_ev);
    event_add(read_ev, NULL);
    event_base_dispatch(base);
    //--------------
    event_base_free(base);
}
/**
 * 创建一个新线程,在新线程里初始化libevent读事件的相关设置,并开启event_base_dispatch
 */
void init_read_event_thread(int sock){
    pthread_t thread;
    pthread_create(&thread,NULL,init_read_event,(void*)sock);
    pthread_detach(thread);
}
int main() {
    cout << "main started" << endl; // prints Hello World!!!
    cout << "Please input server IP:"<<endl;
    char ip[16];
    cin >> ip;
    cout << "Please input port:"<<endl;
    int port;
    cin >> port;
    cout << "ServerIP is "<<ip<<" ,port="<<port<<endl;
    int socket_fd = connectServer(ip, port);
    cout << "socket_fd="<<socket_fd<<endl;
    init_read_event_thread(socket_fd);
    //--------------------------
    char buffer[BUF_SIZE];
    bool isBreak = false;
    while(!isBreak){
        cout << "Input your data to server(\'q\' or \"quit\" to exit)"<<endl;
        //cin >> buffer;
        cin.getline(buffer,BUF_SIZE);

        if(strcmp("q", buffer)==0 || strcmp("quit", buffer)==0){
            isBreak=true;
            close(socket_fd);
            break;
        }
        cout << "Your input is "<<buffer<<endl;
        int write_num = write(socket_fd, buffer, strlen(buffer));
        cout << write_num <<" characters written"<<endl;
        sleep(2);
    }
    cout<<"main finished"<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值