libevent服务器页面显示,基于 libevent 开源框架实现的 web 服务器

自己实现的如有缺漏欢迎提出

直接代码 一切皆在代码中

首先是 主函数文件 和 头文件

头文件:#ifndef _HEAD_H_

#define _HEAD_H_

#include

#include

#include

#include

#include

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

int judge_type_dir_or_nondir(const char* name);

int send_dir_asheml(struct bufferevent *bufev, char *dirname, void *arg);

struct evconnlistener* libev_start(struct event_base*base, const char* Ip,int Port);

int send_html_head(struct bufferevent* bufev, int stat_no, const char* stat_desc, char* type);

const char *get_file_type(const char *name);

int send_file(struct bufferevent *bufev,char* file);

#endif

主函数文件:// File Name: main.c

// Author: jiujue

// Created Time: 2019年04月05日 星期五 19时54分48秒

#include "head.h"

int main(int argc, const char* argv[])

{

if(argc 

{

printf("argument not enough\neg:./app Ip Port sourceDir\n");

exit(1);

}

int ret = chdir(argv[3]);

if(-1 == ret)

{

perror("chdir error");

exit(1);

}

else

{

printf("chdir successful,to -> %s\n",argv[3]);

}

struct event_base* base = event_base_new();

struct evconnlistener* listen = libev_start(base,argv[1],atoi(argv[2]));

event_base_dispatch(base);

evconnlistener_free(listen);

event_base_free(base);

return 0 ;

}

接下来是 调用libevent框架了 (重头戏来了 注意回调的设置哦):// File Name: _libev.c

// Author: jiujue

// Created Time: 2019年04月05日 星期五 19时54分08秒

#include "head.h"

#define PATH_OF_404_ "404.html"

void read_cb(struct bufferevent* bufev, void* arg)

{

printf("<<<<<<<<<<<<<<<<<<<<<<<<<<

char buf[1024] = {0}, method[12] = {0}, path[1024] = {0}, protocol[12] = {0};

bufferevent_read(bufev,buf,sizeof(buf));

//printf("-----------------------recv http request :%s\n",buf);

sscanf(buf,"%s %s %s",method,path,protocol);

char *file = path+1;

if(0 == (strcmp(path,"/") ) )

{

file = (char*)"./";

}

int isFile = judge_type_dir_or_nondir(file);

printf("fffffffff          is %d \n",isFile);

if(0 == isFile)

{//is palin file

printf("send file >%s\n",file);

send_file(bufev,file);

}

if(isFile == 1){//is dir

printf("send dir >%s\n",file);

send_html_head(bufev,200,"OK",(char*)"text/html");

send_dir_asheml(bufev,file,NULL);

}

else if(-1 == isFile)

{//is not found file or directory

printf("send 404 >%s\n",file);

send_file(bufev,PATH_OF_404_);

}

}

void write_cb(struct bufferevent* bufev, void* arg)

{

struct sockaddr_in *cli = (struct sockaddr_in*)arg;

char buf[1024] = {0};

printf("Sent respond to cli,Ip ->%s and Port ->%d\n",

inet_ntop(AF_INET,&(cli->sin_addr.s_addr), buf,sizeof(buf)),

ntohs(cli->sin_port) );

}

void event_cb(struct bufferevent* bufev, short ev, void* arg)

{

printf("event_cb successful\n");

if(ev & BEV_EVENT_EOF)

{

struct sockaddr_in *cli = (struct sockaddr_in*)arg;

char buf[1024] = {0};

printf("Have client disconnect, Ip ->%s and Port ->%d\n",

inet_ntop(AF_INET,&(cli->sin_addr.s_addr), buf,sizeof(buf)),

ntohs(cli->sin_port) );

}

if(ev & BEV_EVENT_ERROR )

{

printf("******************************** Happy Error******************************\n");

}

bufferevent_free(bufev);

}

void listener_cb(struct evconnlistener *listener,

evutil_socket_t fd, struct sockaddr* cli,

int cli_len, void* arg)

{

printf("<<<<<<<<<<<<<<<<<<<

struct event_base* base = (struct event_base*)arg;

struct bufferevent* bufev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);

bufferevent_setcb(bufev, read_cb, write_cb, event_cb,cli);

bufferevent_enable(bufev,EV_READ);

}

struct evconnlistener* libev_start(struct event_base*base, const char* Ip,int Port)

{

struct sockaddr_in ser;

ser.sin_family = AF_INET;

ser.sin_port = htons(Port);

inet_pton(AF_INET,Ip,&(ser.sin_addr.s_addr));

struct evconnlistener* ret =  evconnlistener_new_bind(base, listener_cb, base,

LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE, 128,

(struct sockaddr *)&ser, sizeof(ser));

if(ret == NULL)

{

return NULL;

}

return ret;

}

然后是 发送文件和目录的回调

文件的:#include "head.h"

int send_file(struct bufferevent *bufev,char* file)

{

int ffd = open(file,O_RDONLY);

if(-1 == ffd)

{

printf("sourceFilePath : %s\n",file);

perror("open sourceFile error");

}

char file_read_buf[1024];

int read_len = 0;

char * type = get_file_type(file);

send_html_head(bufev,200, "OK", type);

while((read_len=read(ffd, file_read_buf,sizeof(file_read_buf))) > 0)

{

if(0 == read_len)

{

break;

}

bufferevent_write(bufev,file_read_buf,read_len);;

file_read_buf[strlen(file_read_buf)+1] = '\n';

printf("send message :%s\n",file_read_buf);

memset(file_read_buf,0,sizeof(file_read_buf));

}

printf("close ...\n");

close(ffd);

return 0;

}

目录的(这里拼接网页的时候要细心 非常细心的那种 ):// File Name: _send_dir.c

// Author: jiujue

// Created Time: 2019年04月05日 星期五 19时27分18秒

#include "head.h"

#define MAXFORGTML_ 4096

int send_dir_asheml(struct bufferevent *bufev, char *dirname, void* arg)

{

printf("******************send_dir name is %s\n",dirname);

char* buf_dir_html = (char *)malloc(MAXFORGTML_);

struct dirent **ptr;

int dir_total_num = scandir(dirname,&ptr,NULL,alphasort);

//html head

sprintf(buf_dir_html,"HTML>                                                                    

                                        Curent dir:%s                                                                                                                

Curretn Dir Content:%s 

                                        
NameSizeType

bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html));

for(int i=0;i

{

char buf_current_name[1024] = {0};

if( 0 == strcmp(dirname,"./"))

{

sprintf(buf_current_name,"%s%s",dirname,ptr[i]->d_name);

}

else

{

sprintf(buf_current_name,"%s/%s",dirname,ptr[i]->d_name);

}

printf("++++++++++++++++++++send cur dir >%s\n",buf_current_name);

struct stat st;

memset(&st,0,sizeof(st));

stat(buf_current_name,&st);

sprintf(buf_dir_html,

"

                                             %s                                            %ld                                            %s                                        ",

buf_current_name,

ptr[i]->d_name,st.st_size,

judge_type_dir_or_nondir(buf_current_name)!= 0?"dir":"plain file");

bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html));

memset((char*)buf_dir_html,0,sizeof(buf_dir_html));

}

//html end

sprintf(buf_dir_html,

"

                                                                    ");

bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html));

bufferevent_write(bufev,"\r\n",2);

free(buf_dir_html);

return 0;

}

最后就是一些小函数了: 判断文件类型 和是否为目录:

判断文件类型(这里如果出问题 打开图片等时会出现问题):// File Name: _get_file_type.c

// Author: jiujue

// Created Time: 2019年04月06日 星期六 19时14分07秒

#include "head.h"

const char *get_file_type(const char *name)

{

char* dot;

dot = strrchr(name, '.');

if (dot == NULL)

return "text/plain; charset=utf-8";

if (strcmp(dot, ".html") == 0 || strcmp(dot, ".htm") == 0)

return "text/html; charset=utf-8";

if (strcmp(dot, ".jpg") == 0 || strcmp(dot, ".jpeg") == 0)

return "image/jpeg";

if (strcmp(dot, ".gif") == 0)

return "image/gif";

if (strcmp(dot, ".png") == 0)

return "image/png";

if (strcmp(dot, ".css") == 0)

return "text/css";

if (strcmp(dot, ".au") == 0)

return "audio/basic";

if (strcmp( dot, ".wav" ) == 0)

return "audio/wav";

if (strcmp(dot, ".avi") == 0)

return "video/x-msvideo";

if (strcmp(dot, ".mov") == 0 || strcmp(dot, ".qt") == 0)

return "video/quicktime";

if (strcmp(dot, ".mpeg") == 0 || strcmp(dot, ".mpe") == 0)

return "video/mpeg";

if (strcmp(dot, ".vrml") == 0 || strcmp(dot, ".wrl") == 0)

return "model/vrml";

if (strcmp(dot, ".midi") == 0 || strcmp(dot, ".mid") == 0)

return "audio/midi";

if (strcmp(dot, ".mp3") == 0)

return "audio/mpeg";

if (strcmp(dot, ".ogg") == 0)

return "application/ogg";

if (strcmp(dot, ".pac") == 0)

return "application/x-ns-proxy-autoconfig";

return "text/plain; charset=utf-8";

}

判断是否为目录:// File Name: _judge_type.c

// Author: jiujue

// Created Time: 2019年04月05日 星期五 20时54分34秒

#include "head.h"

int judge_type_dir_or_nondir(const char* name)

{

struct stat st;

int ret = stat(name,&st);

if(-1 == ret)

{

return -1;

}

if(S_ISREG(st.st_mode))

{

return 0;

}

if(S_ISDIR(st.st_mode))

{

return 1;

}

else

{

return 2;

}

}

#if 0

int main(int argc,char* argv[])

{

int ret =  judge_type_dir_or_nondir(argv[1]);

if(ret == 1)

{

printf("is dir ");

}

if(ret == 0)

{

printf("is  file");

}

return 0;

}

#endif

注:以上代码已测验,基本没有问题(bug 肯定有 欢迎提出)

原文链接:http://www.cnblogs.com/jiujue/p/10707153.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Libevent的TCP服务器可以通过以下几个步骤实现: 1. 引入Libevent库:在代码中添加#include <event2/event.h>头文件,并在链接选项中添加-l event选项来引入Libevent库。 2. 创建event_base:使用event_base_new()函数创建一个event_base对象,这个对象将被用来管理所有的事件。 3. 创建监听socket:使用socket()函数创建一个TCP监听socket,并设置为非阻塞模式。然后使用event_new()函数创建一个event对象,用于监听该socket上的事件。 4. 绑定监听socket:使用bind()函数将监听socket绑定到指定的端口上。 5. 设置监听socket监听状态:使用listen()函数将监听socket设置为监听状态,并将event对象与监听socket绑定起来。 6. 处理事件循环:使用event_base_dispatch()函数进入事件循环,等待事件的发生。 7. 处理连接事件:当有新的连接请求到达监听socket时,Libevent会触发EV_READ事件,此时可以使用accept()函数接收连接,并使用event_new()函数创建一个event对象,用于监听连接socket上的事件。 8. 处理读写事件:当有数据到达连接socket时,Libevent会触发EV_READ事件,此时可以使用recv()函数接收数据,并使用event_add()函数将event对象加入到event_base中,监听连接socket上的EV_WRITE事件。当可以向连接socket写入数据时,Libevent会触发EV_WRITE事件,此时可以使用send()函数向连接socket写入数据。 以上就是基于Libevent的TCP服务器的基本实现步骤。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值