基于 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服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...
随机推荐
- C# 替换Word文本—— 用文档、图片、表格替换文本
编辑文档时,对一些需要修改的字符或段落可以通过查找替换的方式,快速地更改.在C# 在word中查找及替换文本一文中,主要介绍了在Word中以文本替换文本的方法,在本篇文章中,将介绍如何用一篇Word文 ...
- DRUID连接池配置详情
DRUID介绍 DRUID是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0.DBCP.PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针 ...
- 关于ASL(平均查找长度)的简单总结
ASL(Average Search Length),即平均查找长度,在查找运算中,由于所费时间在关键字的比较上,所以把平均需要和待查找值比较的关键字次数成为平均查找长度. 它的定义是这样的: 其中n ...
- 45个值得收藏的 CSS 形状
摘要: CSS炫技. 原文:45个值得收藏的 CSS 形状 作者:前端小智 Fundebug经授权转载,版权归原作者所有. CSS能够生成各种形状.正方形和矩形很容易,因为它们是 web 的自然形状. ...
- 前端vue系列-起始篇 vue的基本认知
hi,大家伙,我是佛系大大,很高兴与你们一起沟通,学习,进步. 很久不更新博客了,现在回来再写博客,尽然是有些怀念的感觉,幸福的感觉.因为写博客,内心会很宁静,沉浸在自己的世界中,是很幸福的一件事.当 ...
- android 请求接口报错 org.apache.http.conn.HttpHostConnectException: Connection to http://192.168.1.90:9090 refused
No Network Security Config specified, using platform defaultI/System.out: org.apache.http.conn.HttpH ...
- Android之OkHttp详解
文章大纲 一.OkHttp简介二.OkHttp简单使用三.OkHttp封装四.项目源码下载 一.OkHttp简介 1. 什么是OkHttp 一般在Java平台上,我们会使用Apache Htt ...
- 2018-01-12 Antlr4添加中文变量赋求值,括号,各种问题
中文编程知乎专栏原文地址 例程(更多测试用例在此): 基数=100 基数×(基数+1)÷2 => 求值为5050 续上文Antlr4实现数学四则运算, 修改的语法规则部分: 程序: 声明+; 声 ...
- psql 关于主键自增的问题
在psql中往往我们需要设置一个自增的主键id字段,psql中不像SQL Server那样点选 打钩傻瓜式就能设置好的,是需要创建序列的:CREATE SEQUENCE,关键字SEQUENCE. 我们 ...
- Windows Cluster 添加新节点--验证报错
今天给既有Windows Cluster 添加节点时,验证总是不通过.报错信息为 防火墙未正确配置为故障转移群集.现将处理步骤汇总如下. 1.错误具体信息 报错的位置 --[验证警告] 的步骤中发现错 ...