http协议以及epoll实现http

http协议

URL
在WWW上,每一信息资源都有统一的且在网上唯一的地址,该地址就叫URL(Uniform Resource Locator,统一资源定位符),就是指网络地址。

请求消息 - 浏览器发送给服务器
四部分
请求行:
请求说明类型:
GET:请求指定的页面信息,并返回实体主体
POST:向指定资源提交数据进行处理请求。数据被包含在请求体中,POST可能会导致新的资源的建立或者已有资源的修改。
访问的资源,以及使用的http版本
eg:
GET /*.TXT /HTTP1.1\r\n; //中间要空格 结尾有\r\n
请求头
说明服务器要使用的附加信息。(不重要)
空行:
r\n 必须有
请求的数据
可有可无(当为GET就一定没有,当为POST时就为请求行的第二部分/.*TXT)

响应消息 - 服务器给浏览器发
四部分
状态行
http协议版本号,状态码,状态信息
eg: HTTP1.1 200 OK
在这里插入图片描述
消息报头
在这里插入图片描述
在这里插入图片描述
空行

响应正文
请求的数据

正则表达式

正则表达式速查表

#define MAX 1024

void epoll_run(int port)
{
	//创建一个根节点
	int epfd = epoll_create(MAX);
	//添加监听的节点
	int lfd = init_lfd;
	//等待事件
	struct epoll_event all[MAX];
	while(1){
		int ret = epoll_wait(epfd,all,MAX,-1);
		for(int i = 0; i < ret; ++i){
			struct epoll_event *p = &all[i];
			if(!(p->events & EPOLLIN)){
				continue;//不是读事件 默认不处理
			}
			if(pev->data.fd == lfd){
				do_accept(epfd,lfd);
			}else {
				
			}
		}
	}
}

void do_read(int cfd)
{
	char buf[1024];
	get_line(cfd,buf,sizeof(buf));
	if(strcasecmp("get",buf) == 0){
		http_request(buf,cfd);
	}
}

void http_request(const char *buf,int cfd)
{
	char method[12],path[1024],protocol[12];
	sscanf(buf,"%[^ ] %[^ ] %[^ ]",method,path,protocol);

	//转码 将不能识别的中文乱码 - > 中文
	//解码
	decode_str(path,path);
	
	char *file = path + 1;
	//若果没有指定访问资源,默认显式资源目录内容
	if(strcmp(path,"/") == 0){
		file = "./";//就是资源目录的当前位置
	}
	//获取文件属性
	struct stat st;
	int ret = stat(file,&st);
	//判断是目录还是文件
	if(S_ISDIR(st.st_mode))
	{
		//是目录
		//报头
		send_respond_head(cfd,200,"OK","text/html",-1);
		//发送目录
		send_dir(cfd,file);
	}
	else if(S_ISREG(st.st_mode))
	{
		//是文件
		//发送消息报头
		send_respond_head(cfd,200,"OK","text/plain",st.st_size());
		//发送文件内容
		send_file(cfd,file);
	}
}

void send_dir(int cfd, const char *dirname)
{
	//拼凑一个html页面	
	char ebuf[4096];
	char buf[4096];
	sprintf(buf,"<html><head><title>目录名:%s</title></head>",dirname);
	char path[1024];
#if 0
	DIR *dir = opendir(dirname);//打开目录
	struct dirent* ptr = NULL;
	while((ptr = readdir(dir)) != NULL){
		char *name = ptr->d_name;
		//这里再写到html中
	}
	close(dir);//第一种方式
#endif
	struct dirent** ptr;
	int len = scandir(dirname,&ptr,NULL,alphasort);//返回值为有多少个文件
	for(int i = 0; i < len; i++){
		char *name = ptr[i]->d_name;
		sprintf(path,"%s/%s",dirname,name);
		struct stat st;
		stat(path,&st);

		//转码
		encode(ebuf,sizeof(ebuf),name);

		if(S_ISREG(st.st_mode)){
			sprintf(buf+strlen(buf),"<tr><td><a herf=\"%s\">%s</a></td><td>%ld</td></tr>",ebuf,name,(long)st.st_size);
		}
		else if(S_ISDIR(st.st_mode)){
			sprintf(buf+strlen(buf),"<tr><td><a herf=\"%s/\">%s/</a></td><td>%ld</td></tr>",ebuf,name,(long)st.st_size);
		}
		send(cfd, buf, sizeof(buf), 0);
		memset(buf, 0, sizeof(buf));
	}
	sprintf(buf+strlen(buf),"</table></body></html>");
	send(cfd, buf, sizeof(buf), 0);
}

void send_respond_head(int cfd,int no,const char *desp,const char *type,long len)
{
	char buf[1024];
	//状态行
	sprintf(buf,"http/1.1 %d %s\r\n",no,desp);
	send(cfd,buf,sizeof(buf),0);
	//消息报头
	sprintf(buf,"Content-Type:%s\r\n",type);
	sprintf(buf+strlen(buf),"Content-Length:%ld\r\n",len);
	send(cfd,buf,sizeof(buf),0);
	//空行
	send(cfd,"\r\n",2,0);
}

void send_file(int cfd,const char* file)
{
	//打开文件
	int fd = open(file,O_RDONLY);
	char buf[4096];
	int len = 0;
	while((len = read(fd,buf,sizeof(buf))) > 0){
		send(cfd,buf,len,0);
	}
	close(fd);
}

int get_line(int sock,char *str,int size)
{
	int i = 0;
	char c = '\0';
	int n;

	while((i < size - 1) && (c != '\n')){
		n = recv(sock,&c,1,0);
		if(n > 0){
			if(c == '\r'){
				n = recv(sock,&c,1,MSG_PEEK);
				if((n > 0) && (c == '\n')){
					recv(sock,&c,1,0);
				}
				else {
					c = '\n';
				}
			}
			str[i] = c;
			++i;
		}
		else {
			c = '\n';
		}
	}
	str[i] = '\0';

	return i;
}

void do_accept(int epfd,int lfd)
{
	struct sockaddr_in cile;
	socklen_t cile_t = sizeof(cile);
	
	int cfd = accept(lfd,(struct sockaddr *)&cile,&cile_t);

	int flag = fcntl(cfd,F_GETFL);
	flag |= O_NONBLOCK;
	fcntl(cfd,F_SETFL,flag);//设置边沿非阻塞

	struct epoll_event ev;
	ev.data.fd = cfd;
	ev.events = EPOLLIN | EPOLLET;//边沿非阻塞
	
	epoll_ctl(epfd,EPOLL_CTL_ADD,cfd,&ev);
}

int init_lfd(int epfd,int port)
{
	int lfd = socket(AF_INET,SOCK_STREAM,0);
	
	struct sockaddr_in serv;
	serv.sin_family = AF_INET;
	serv.sin_port = htons(port);
	serv.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(lfd,(struct sockaddr *)&serv,sizeof(serv));
	
	listen(lfd,128);

	epoll_add(epfd,)
	
	struct epoll_event ev;
	ev.events = EPOLLIN;
	ev.data.fd = lfd;
	epoll_ctl(epfd,EPOLL_CTL_ADD,lfd,&ev);

	return lfd; 
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值