自己实现的如有缺漏欢迎提出
直接代码 一切皆在代码中
首先是 主函数文件 和 头文件
头文件:#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:%sCurretn Dir Content:%s
Name | Size | Type |
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