libevent学习---简单http server实现

本文介绍了如何利用libevent库实现一个简单的HTTP服务器。主要步骤包括:接收HTTP请求并将其输出到标准输出,以及构建HTTP响应,包含响应行、响应头(如Server, Content-Type, Content-Length)和响应报文。文中并未涉及优化和性能方面的内容,代码已上传至GitHub。" 51112676,5612665,Ubuntu Server:FTP与SSH服务安装指南,"['linux', 'ftp', 'ssh']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

libevent中有evhttp实现了http server,看了一下,4000多行代码。

其实实现一个http server的步骤很简单,无非就是业务上的内容,至于优化和性能都是写代码及架构设计模式的问题,这部分我太菜了就不说了。

简单说下这篇博文的思路:
1.作为一个简单的HTTP server,在read callback里面,直接write http request到标准输出。
2.另外在read callback里面,向libevent中提供的evbuffer 里面构造响应,http响应由如下内容组成:

(a) 响应行:状态 相应码等
(b) 响应头:这里我就写了Server Content-Type Content-Length等
(c) 响应报文:简单的h5代码,用两个\r\n和response head隔开

代码见:gayhub

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>

#include <event2/event.h>
#include <event2/bufferevent.h>
#include <event2/buffer.h>
#include <sys/socket.h>
#include <string.h>

#include <netinet/in.h>
#include <netdb.h>

void errorcb(struct bufferevent*bev,short events,void *ptr)
{
    printf("in errorcb\r\n");
    if(events&BEV_EVENT_CONNECTED)
    {
    printf("ok connected\r\n");
    }
    else if(events&(BEV_EVENT_ERROR|BEV_EVENT_EOF))
    {
    struct event_base *base=ptr;
    printf("closing... \r\n");
    bufferevent_free(bev);

    event_base_loopexit(base,NULL);
    }
}

void readcb(struct bufferevent*bev,void *arg )
{
    printf("in readcb\r\n");
    struct evbuffer *input;
    struct evbuffer *output;
    char *request_line;
    size_t len;
    input = bufferevent_get_input(bev);
    output = bufferevent_get_output(bev);


    size_t input_len = evbuffer_get_length(input);
    while(1)
    {
    request_line = evbuffer_readln(input,&len,EVBUFFER_EOL_CRLF);

    if(NULL==request_line)
    {
        //printf("evbuffer_readln error\r\n");
        free(request_line);
        break;
    }
    else
    {
        char request_buf[256];
        snprintf(request_buf,len+5,"> %s\r\n",request_line);
        write(1,request_buf,strlen(request_buf));
    }
    }
    //构造响应报文
    char content[]="<html><head><title>This is title</title></head><body><h1>Hello</h1></body></html>";
    char tmp[]="HTTP/1.1 200 OK\r\nServer: ZhangXiao\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n%s";
    int contentlen=strlen(content);
    char response[256];

    snprintf(response,256,tmp,contentlen,content);
    char *p = response;
    evbuffer_add(output,p,strlen(response));


    free(request_line);

}

void do_accept(evutil_socket_t listener,short event,void*arg)
{
    printf("in accept\r\n");
    struct event_base *base = (struct event_base *)arg;
    struct sockaddr_in ss;
    socklen_t slen = sizeof(ss);
    int fd = accept(listener,(struct sockaddr *)&ss,&slen);
    assert(fd>0);


    struct bufferevent *bev;
    evutil_make_socket_nonblocking(fd);
    //使用buffer_socket_new创建一个struct bufferevent*,关联fd
    //托管给event_base,BEV_OPT_CLOSE_ON_FREE表示释放bufferevent的时候
    //关闭底层套接字等...
    bev = bufferevent_socket_new(base,fd,BEV_OPT_CLOSE_ON_FREE);


    //设置对应的回调函数
    bufferevent_setcb(bev,readcb,NULL,errorcb,base);

    bufferevent_enable(bev,EV_READ|EV_WRITE);//event_add
}

int main(int argc,char **argv)
{
    evutil_socket_t listener;
    struct sockaddr_in sin;
    struct event_base *base;
    struct event* listener_event;

    base = event_base_new();
    assert(NULL!=base);

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = 0;
    sin.sin_port=htons(1025);

    listener = socket(AF_INET,SOCK_STREAM,0);
    assert(listener>0);

    evutil_make_socket_nonblocking(listener);//fcntl的封装

    if(bind(listener,(struct sockaddr*)&sin,sizeof(sin))<0)
    {
    perror("bind");
    return -1;
    }

    if(listen(listener,16)<0)
    {
    perror("listen");
    return -1;
    }

    listener_event=event_new(base,listener,EV_READ|EV_PERSIST,do_accept,(void*)base);
    event_add(listener_event,NULL);//add to pending event lists
    event_base_dispatch(base);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值