/* 原创文章 转载请附上原链接: 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 服务器的更多相关文章

  1. Fenix – 基于 Node.js 的桌面静态 Web 服务器

    Fenix 是一个提供给开发人员使用的简单的桌面静态 Web 服务器,基于 Node.js 开发.您可以同时在上面运行任意数量的项目,特别适合前端开发人员使用. 您可以通过免费的 Node.js 控制 ...

  2. 基于 libevent 开发的 C++ 11 高性能网络服务器 evpp(360的作品)

    evpp是一个基于libevent开发的现代化C++11高性能网络服务器,自带TCP/UDP/HTTP等协议的异步非阻塞式的服务器和客户端库. 特性: 现代版的C++11接口 非阻塞异步接口都是C++ ...

  3. 基于Java Mina框架的部标jt808服务器设计和开发

    在开发部标GPS平台中,部标jt808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言.需要购买jt808GPS服务器源码 ...

  4. 基于Facebook开源框架SocketRocket的即时通讯

    SocketRocket 介绍: SocketRock 是 Facebook 开源的框架,基于 WebSocket 客户端类库,适用于 iOS.Mac OS.tv OS.GitHub 传送门:http ...

  5. 基于Java Mina框架的部标808服务器设计和开发

    在开发部标GPS平台中,部标808GPS服务器是系统的核心关键,决定了部标平台的稳定性和行那个.Linux服务器是首选,为了跨平台,开发语言选择Java自不待言. 我们为客户开发的部标服务器基于Min ...

  6. 基于corosync+pacemaker+drbd+LNMP做web服务器的高可用集群

    实验系统:CentOS 6.6_x86_64 实验前提: 1)提前准备好编译环境,防火墙和selinux都关闭: 2)本配置共有两个测试节点,分别coro1和coro2,对应的IP地址分别为192.1 ...

  7. 基于NPOI开源框架写的ExcelHelper【转载】

    namespace ExcelTest { using System; using System.Collections.Generic; using System.Data; using Syste ...

  8. springboot完整项目,基于人人开源框架

    这是前端和数据库 下载链接只有31天有效,需要的,请联系QQ2319899766 下载链接密码: 9ksz 这个是后端代码 链接只有31天有效时间,链接失效请联系QQ2319899766提供下载链接 ...

  9. TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现

    目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...

随机推荐

  1. ArcGIS API for JavaScript 4.x 本地部署之Nginx法

    上篇ArcGIS API for JavaScript 4.x 离线配置之IIS法提到,如何用IIS配置ArcGIS jsAPI: 本篇则使用http下的Nginx配置,其原理基本一致.https的部 ...

  2. Docker 创建 Crowd3.3.2 以及打通 Jira Software7.12.3和Confluence6.12.2 SSO 单点登录

    目录 目录 1.介绍 1.1.什么是Crowd? 2.Crowd 的官网在哪里? 3.如何下载安装? 4.对 Crowd 进行配置 4.1.破解 Crowd 第一步 4.2.破解 Crowd 第二步, ...

  3. Exp3免杀原理与实践 20164312 马孝涛

    1.实验要求   1.1 正确使用msf编码器(0.5分),msfvenom生成如jar之类的其他文件(0.5分),veil-evasion(0.5分),加壳工具(0.5分),使用shellcode编 ...

  4. AI - TensorFlow - 过拟合(Overfitting)

    过拟合 过拟合(overfitting,过度学习,过度拟合): 过度准确地拟合了历史数据(精确的区分了所有的训练数据),而对新数据适应性较差,预测时会有很大误差. 过拟合是机器学习中常见的问题,解决方 ...

  5. 【视频】Entity Framework Core 2.* 入门教程

    视频专辑在B站上:https://www.bilibili.com/video/av34462368/ 内容暂时如下,还在更新中: 1. 简介 & 创建Model,生成数据库 2. 在ASP. ...

  6. [intellij IDEA]导入eclipse项目

    1.因为最近eclipse在更新代码时经常卡死,就想将eclipse的项目迁移到idea.特意写下自己的经验,给迁移时遇到困难的朋友一些帮助 File -> new ->project f ...

  7. 从一个国内普通开发者的视角谈谈Sitecore

    一.Sitecore是个神马玩意 简而言之,Sitecore就是一个基于ASP.NET技术的CMS系统,它不仅具有传统Web CMS的所有功能,还集成了Marketing营销(当然,这个功能价格不菲) ...

  8. Python爬虫入门教程 50-100 Python3爬虫爬取VIP视频-Python爬虫6操作

    爬虫背景 原计划继续写一下关于手机APP的爬虫,结果发现夜神模拟器总是卡死,比较懒,不想找原因了,哈哈,所以接着写后面的博客了,从50篇开始要写几篇python爬虫的骚操作,也就是用Python3通过 ...

  9. TabBottomFragmentLayout【自定义底部选项卡区域(搭配Fragment)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 自定义底部选项卡布局LinearLayout类,然后配合Fragment,实现切换Fragment功能. 缺点: 1.底部选项卡区域 ...

  10. springboot~如何去掌握它(新手可以看看)

    springboot~如何去掌握它 主讲:仓储大叔 每讲40分钟 架构图 graph LR App-->A Web-->A A(zuul proxy)-->B(eureka serv ...