基于 libevent 开源框架实现的 web 服务器
/* 原创文章 转载请附上原链接: https://www.cnblogs.com/jiujue/p/10707153.html */
自己实现的如有缺漏欢迎提出
直接代码 一切皆在代码中
首先是 主函数文件 和 头文件
头文件:
#ifndef _HEAD_H_
#define _HEAD_H_ #include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<math.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#include <unistd.h>
#include <event2/event.h>
#include <event2/listener.h>
#include <event2/bufferevent.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <arpa/inet.h> 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();
} int ret = chdir(argv[]);
if(- == ret)
{
perror("chdir error");
exit();
}
else
{
printf("chdir successful,to -> %s\n",argv[]);
} struct event_base* base = event_base_new(); struct evconnlistener* listen = libev_start(base,argv[],atoi(argv[])); event_base_dispatch(base); evconnlistener_free(listen);
event_base_free(base); return ;
}
接下来是 调用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("<<<<<<<<<<<<<<<<<<<<<<<<<<<,,Happen read_cb\n");
char buf[] = {}, method[] = {}, path[] = {}, protocol[] = {};
bufferevent_read(bufev,buf,sizeof(buf));
//printf("-----------------------recv http request :%s\n",buf);
sscanf(buf,"%s %s %s",method,path,protocol);
char *file = path+;
if( == (strcmp(path,"/") ) )
{
file = (char*)"./";
} int isFile = judge_type_dir_or_nondir(file);
printf("fffffffff is %d \n",isFile);
if( == isFile)
{//is palin file
printf("send file <name>>%s\n",file);
send_file(bufev,file);
}
if(isFile == ){//is dir
printf("send dir <name>>%s\n",file);
send_html_head(bufev,,"OK",(char*)"text/html");
send_dir_asheml(bufev,file,NULL);
}
else if(- == isFile)
{//is not found file or directory
printf("send 404 <name>>%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[] = {};
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[] = {};
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("<<<<<<<<<<<<<<<<<<<<,,,,,,,,, listener_cb successful\n");
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, ,
(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(- == ffd)
{
printf("sourceFilePath : %s\n",file);
perror("open sourceFile error"); } char file_read_buf[];
int read_len = ; char * type = get_file_type(file); send_html_head(bufev,, "OK", type); while((read_len=read(ffd, file_read_buf,sizeof(file_read_buf))) > )
{
if( == read_len)
{
break;
}
bufferevent_write(bufev,file_read_buf,read_len);;
file_read_buf[strlen(file_read_buf)+] = '\n';
printf("send message :%s\n",file_read_buf);
memset(file_read_buf,,sizeof(file_read_buf));
} printf("close ...\n");
close(ffd);
return ;
}
目录的(这里拼接网页的时候要细心 非常细心的那种 ):
// 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,"<!doctype HTML>\
<html>\
<head>\
<title>Curent dir:%s</title>\
</head>\
<body>\
<h1>Curretn Dir Content:%s </h1>\
<table>\
<tr>\
<td>Name</td><td>Size</td><td>Type</td>\
</tr>",dirname,dirname);
bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html)); for(int i=;i<dir_total_num;++i)
{
char buf_current_name[] = {};
if( == 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 <name>>%s\n",buf_current_name);
struct stat st;
memset(&st,,sizeof(st));
stat(buf_current_name,&st); sprintf(buf_dir_html,
"<tr>\
<td><a href=\"%s\">%s</a></td>\
<td>%ld</td>\
<td>%s</td>\
</tr>",
buf_current_name,
ptr[i]->d_name,st.st_size,
judge_type_dir_or_nondir(buf_current_name)!= ?"dir":"plain file");
bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html));
memset((char*)buf_dir_html,,sizeof(buf_dir_html));
} //html end
sprintf(buf_dir_html,
"</table>\
</body>\
</html>");
bufferevent_write(bufev,buf_dir_html,strlen(buf_dir_html));
bufferevent_write(bufev,"\r\n",); free(buf_dir_html);
return ;
}
最后就是一些小函数了: 判断文件类型 和是否为目录:
判断文件类型(这里如果出问题 打开图片等时会出现问题):
// 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") == || strcmp(dot, ".htm") == )
return "text/html; charset=utf-8";
if (strcmp(dot, ".jpg") == || strcmp(dot, ".jpeg") == )
return "image/jpeg";
if (strcmp(dot, ".gif") == )
return "image/gif";
if (strcmp(dot, ".png") == )
return "image/png";
if (strcmp(dot, ".css") == )
return "text/css";
if (strcmp(dot, ".au") == )
return "audio/basic";
if (strcmp( dot, ".wav" ) == )
return "audio/wav";
if (strcmp(dot, ".avi") == )
return "video/x-msvideo";
if (strcmp(dot, ".mov") == || strcmp(dot, ".qt") == )
return "video/quicktime";
if (strcmp(dot, ".mpeg") == || strcmp(dot, ".mpe") == )
return "video/mpeg";
if (strcmp(dot, ".vrml") == || strcmp(dot, ".wrl") == )
return "model/vrml";
if (strcmp(dot, ".midi") == || strcmp(dot, ".mid") == )
return "audio/midi";
if (strcmp(dot, ".mp3") == )
return "audio/mpeg";
if (strcmp(dot, ".ogg") == )
return "application/ogg";
if (strcmp(dot, ".pac") == )
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(- == ret)
{
return -;
}
if(S_ISREG(st.st_mode))
{
return ;
}
if(S_ISDIR(st.st_mode))
{
return ;
}
else
{
return ;
} } #if 0
int main(int argc,char* argv[])
{
int ret = judge_type_dir_or_nondir(argv[]);
if(ret == )
{
printf("is dir ");
}
if(ret == )
{
printf("is file");
}
return ;
}
#endif
注:以上代码已测验,基本没有问题(bug 肯定有 欢迎提出)
结语:有问题欢迎提在下方 ,本人在校学生,时间较为充裕, 有时间会回复的。
/* 原创文章 转载请附上原链接: https://www.cnblogs.com/jiujue/p/10707153.html */
基于 libevent 开源框架实现的 web 服务器的更多相关文章
- Fenix – 基于 Node.js 的桌面静态 Web 服务器
Fenix 是一个提供给开发人员使用的简单的桌面静态 Web 服务器,基于 Node.js 开发.您可以同时在上面运行任意数量的项目,特别适合前端开发人员使用. 您可以通过免费的 Node.js 控制 ...
- 基于 libevent 开发的 C++ 11 高性能网络服务器 evpp(360的作品)
evpp是一个基于libevent开发的现代化C++11高性能网络服务器,自带TCP/UDP/HTTP等协议的异步非阻塞式的服务器和客户端库. 特性: 现代版的C++11接口 非阻塞异步接口都是C++ ...
- 基于Java Mina框架的部标jt808服务器设计和开发
在开发部标GPS平台中,部标jt808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言.需要购买jt808GPS服务器源码 ...
- 基于Facebook开源框架SocketRocket的即时通讯
SocketRocket 介绍: SocketRock 是 Facebook 开源的框架,基于 WebSocket 客户端类库,适用于 iOS.Mac OS.tv OS.GitHub 传送门:http ...
- 基于Java Mina框架的部标808服务器设计和开发
在开发部标GPS平台中,部标808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言. 我们为客户开发的部标服务器基于Min ...
- 基于corosync+pacemaker+drbd+LNMP做web服务器的高可用集群
实验系统:CentOS 6.6_x86_64 实验前提: 1)提前准备好编译环境,防火墙和selinux都关闭: 2)本配置共有两个测试节点,分别coro1和coro2,对应的IP地址分别为192.1 ...
- 基于NPOI开源框架写的ExcelHelper【转载】
namespace ExcelTest { using System; using System.Collections.Generic; using System.Data; using Syste ...
- springboot完整项目,基于人人开源框架
这是前端和数据库 下载链接只有31天有效,需要的,请联系QQ2319899766 下载链接密码: 9ksz 这个是后端代码 链接只有31天有效时间,链接失效请联系QQ2319899766提供下载链接 ...
- TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现
目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...
随机推荐
- Promise(避免金字塔回调)
前后端分离开发,前端通过接口获取数据,但是有的页面不止一个接口,就会出现金字塔回调,可以通过 Promise 封装请求. request-data.js: function reqData(postu ...
- Dynamics 365 CE在Pre Delete插件中应用Image
微软动态CRM专家罗勇 ,回复327或者20190428可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me! 在插件中限制记录的删除是常见的场景,比如根据statuscode ...
- OGG-02803 Encountered a Data Guard role transition
告警提示其实已经很明显了OGG-02803 Encountered a Data Guard role transition. Alter Extract to SCN 15,756,246 and ...
- 你在为谁工作——IT帮深圳分站2019年3月线下活动回顾
对于工作,在每个人的心中,它所占的份量都是不一样的.有的人活着是为了工作,有的人工作是为了更好的生活. 在3月24日下午,北京.上海与深圳三地我们同步举办了关于工作这个话题的沙龙活动. 我们深圳分站参 ...
- VS2017搭建驱动开发环境WDK
先安装VS2017,然后在安装WDK,WDK会自动关联到VS2017中,不用你任何操作,自动在新建项目中可以找到驱动开发. 如果以上安装完成后,在VS2017中新建项目中没有发现WDK,那么需要进行修 ...
- python进程和线程(六)
协程 协程,又称微线程,纤程.英文名Coroutine.顾名思义,协程是协作式的,也就是非抢占式的程序(线程是抢占式的).协程的关键字是yield,一看到这个就想到了生成器对不对?那就顺便回顾一下生成 ...
- Python + PyQt5 实现美剧爬虫可视工具
美剧<权力的游戏>终于要开播最后一季了,作为马丁老爷子的忠实粉丝,为了能够看得懂第八季复杂庞大的剧情架构,本人想着将前几季再稳固一下,所以就上美剧天堂下载来看,可是每次都上去下载太麻烦了, ...
- 【重学计算机】计组D3章:运算方法与运算器
1. 定点数运算及溢出 定点数加减法:减法化加法,用补码直接相加,忽略进位 溢出:运算结果超出了某种数据类型的表示范围 溢出检测方法:统一思想概括为正正得负或负负得正则溢出,正负或负正不可能溢出 方法 ...
- 《代码整洁之道》(Clean Code)- 读书笔记
一.关于Bob大叔的Clean Code <代码整洁之道>主要讲述了一系列行之有效的整洁代码操作实践.软件质量,不但依赖于架构及项目管理,而且与代码质量紧密相关.这一点,无论是敏捷开发流派 ...
- 【反编译系列】三、反编译神器(jadx)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 今天在看玩Android网站,搜索反编译的时候,才发现有个更好用的反编译工具.特此记录下. 下载 http://www.wanand ...