实现高并发http服务器(一)

  • Post author:
  • Post category:其他



目录


一、项目需求


二、需求分析


1、何为Html页面


2、何为http协议


三、实现Mini型http服务器


1、接受http请求


2、解析http请求


3、响应http请求


一、项目需求

实现一个http 服务器项目,服务器启动后监听80端口的tcp 连接,当用户通过任意一款浏览器(IE、火狐和腾讯浏览器等)访问我们的http服务器,http服务器会查找用户访问的html页面是否存在,如果存在则通过http 协议响应客户端的请求,把页面返回给浏览器,浏览器显示html页面;如果页面不存在,则按照http 协议的规定,通知浏览器此页面不存在(404 NOT FOUND)

二、需求分析

1、何为Html页面




html



,全称Hypertext Markup Language,也就是“超文本链接标示语言”。HTML文本是由 HTML命令组成的描述性文本,HTML 命令可以说明文字、 图形、动画、声音、表格、链接等。 即平常上网所看到的的网页。

demo.html

<html lang=\”zh-CN\”>

<head>

<meta content=\”text/html; charset=utf-8\” http-equiv=\”Content-Type\”>

<title>This is a test</title>

</head>

<body>

<div align=center height=\”500px\” >

<br/><br/><br/>

<h2>This is a test!</h2><br/><br/>

<form action=”commit” method=”post”>

尊姓大名: <input type=”text” name=”name” />

<br/>芳龄几何: <input type=”password” name=”age” />

<br/><br/><br/><input type=”submit” value=”提交” />

<input type=”reset” value=”重置” />

</form>

</div>

</body>

</html>

2、何为http协议


HTTP

协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。

请求格式:




客户端请求


客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。




服务













响应


服务器响应客户端的HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

响应代号

代号描述

服务器上存在请求的内容,并可以响应给客户端

200

OK

客户端的请求有异常,方法有问题

501

Method Not Implemented

服务器收到请求后,因为自生的问题没法响应

500

Internal Server Error

请求的内容不存在

404

NOT FOUND

客户端发送的请求格式有问题等

400

BAD REQUEST

三、实现Mini型http服务器


1、接受http请求





1.  实现按行读取请求头部




因为服务器端接受到的请求为第二点中的格式,是一行行的

//返回值: -1 表示读取出错, 等于0表示读到一个空行, 大于0 表示成功读取一行
int get_line(int sock, char *buf, int size){
	int count = 0;
	char ch = '\0';
	int len = 0;
	
	
	while( (count<size - 1) && ch!='\n'){
		len = read(sock, &ch, 1);
		
		if(len == 1){
			if(ch == '\r'){
				continue;
			}else if(ch == '\n'){
				//buf[count] = '\0';
				break;
			}
			
			//这里处理一般的字符
			buf[count] = ch;
			count++;
			
		}else if( len == -1 ){//读取出错
			perror("read failed");
			count = -1;
			break;
		}else {// read 返回0,客户端关闭sock 连接.
			fprintf(stderr, "client close.\n");
			count = -1;
			break;
		}
	}
	
	if(count >= 0) buf[count] = '\0';
	
	return count;
}





2.  如果碰到两个连续的回车换行,即,意味着请求头部结束



2、解析http请求

void do_http_request(int client_sock){
	int len = 0;
	char buf[256];
	char method[64];
	char url[256];
	char path[256];
	
	
	/*读取客户端发送的http 请求*/
	
	
	//1.读取请求行
	len = get_line(client_sock, buf, sizeof(buf));
	
	if(len > 0){//读到了请求行
		int i=0, j=0;
		while(!isspace(buf[j]) && (i<sizeof(method)-1)){
			method[i] = buf[j];
			i++;
			j++;
		}
		
		method[i] = '\0';
		if(debug) printf("request method: %s\n", method);
		
		if(strncasecmp(method, "GET", i)==0){ //只处理get请求
	        if(debug) printf("method = GET\n");
		
		    //获取url
		    while(isspace(buf[j++]));//跳过白空格
		    i = 0;
		
		    while(!isspace(buf[j]) && (i<sizeof(url)-1)){
			    url[i] = buf[j];
			    i++;
			    j++;
		    }
		
		    url[i] = '\0';
		
		    if(debug) printf("url: %s\n", url);
			
			//继续读取http 头部
		    do{
			    len = get_line(client_sock, buf, sizeof(buf));
			    if(debug) printf("read: %s\n", buf);
			
		    }while(len>0);
			
			//***定位服务器本地的html文件***
			
			//处理url 中的?
			{
				char *pos = strchr(url, '?');
				if(pos){
					*pos = '\0';
					printf("real url: %s\n", url);
				}
			}
			
			sprintf(path, "./html_docs/%s", url);
			if(debug) printf("path: %s\n", path);
			
			//执行http 响应
	
	    }else {
            //非get请求, 读取http 头部,并响应客户端 501 	Method Not Implemented
			fprintf(stderr, "warning! other request [%s]\n", method);
			do{
			    len = get_line(client_sock, buf, sizeof(buf));
			    if(debug) printf("read: %s\n", buf);
			
		    }while(len>0);
			//unimplemented(client_sock);   //在响应时再实现
			
		}		
		
		
	}else {//请求格式有问题,出错处理
		//bad_request(client_sock);   //在响应时再实现
	}
		
}

3、响应http请求

void do_http_response(int client_sock){
    const char *main_header = "HTTP/1.0 200 OK\r\nServer: Martin Server\r\nContent-Type: text/html\r\nConnection: Close\r\n";


    const char * welcome_content = "\
<html lang=\"zh-CN\">\n\
<head>\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\n\
<title>This is a test</title>\n\
</head>\n\
<body>\n\
<div align=center height=\"500px\" >\n\
<br/><br/><br/>\n\
<h2>大家好,欢迎来到xhc的个人主页!</h2><br/><br/>\n\
<form action=\"commit\" method=\"post\">\n\
尊姓大名: <input type=\"text\" name=\"name\" />\n\
<br/>芳龄几何: <input type=\"password\" name=\"age\" />\n\
<br/><br/><br/><input type=\"submit\" value=\"提交\" />\n\
<input type=\"reset\" value=\"重置\" />\n\
</form>\n\
</div>\n\
</body>\n\
</html>";

    char send_buf[64];
    int wc_len = strlen(welcome_content);
    int len = write(client_sock, main_header, strlen(main_header));

    if(debug) fprintf(stdout, "... do_http_response...\n");
    if(debug) fprintf(stdout, "write[%d]: %s", len, main_header);

    len =snprintf(send_buf, 64,"Content-Length: %d\r\n\r\n", wc_len);
    len = write(client_sock, send_buf, len);
    if(debug) fprintf(stdout, "write[%d]: %s", len, send_buf);

    len = write(client_sock, welcome_content, wc_len);
    if(debug) fprintf(stdout, "write[%d]: %s", len, welcome_content);

}

该响应目前只是针对结果的一种编程,并没有主动的去打开文件响应,后续改进



版权声明:本文为qq_51654808原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。