博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
制作HTTP服务器端
阅读量:2177 次
发布时间:2019-05-01

本文共 4527 字,大约阅读时间需要 15 分钟。

HTTP概要

理解Web服务器端

HTTP是Hypertext Transfer Protocol的缩写, Hypertext(超文本)是可以根据客户端请求而跳转的结构化信息。

 

HTTP协议:HTTP是以超文本传输为目的而设计的应用层协议,这种协议同样属于基于TCP/IP实现的协议,因此,可以直接实现HTTP。从结果上看,实现该协议相当于实现Web服务器端。浏览器属于基于套接字的客户端,因此连接到任意Web服务器端时,浏览器内部会创建套接字。只不过浏览器多了项功能,它将服务器端传输的HTML格式的超文本解析为可读性较强的试图。 总之,Web服务器端是以HTTP协议为基础传输超文本的服务器端。

 

HTTP

无状态的Stateless协议

HTTP协议的请求及响应方式设计:

       

服务器端响应客户端请求后立即断开连接,服务器端不会维持客户端状态。即使同一客户端再次发送请求,服务器端也无法辨认出是原先那个,而会以相同方式处理新请求。因此HTTP又称为:"无状态的Stateless协议".

 

为了弥补HTTP无法保持连接的缺点,Web编程中通常会使用CokkieSession技术。

 

请求消息(Request Message)的结构

介绍客户端向服务器端发送的请求消息的结构。Web服务器端需要解析并响应客户端请求,客户端和服务器端之间的数据请求方式标准如图:                                            

                                                         

 

请求行含有请求方式信息。典型的请求方式有GET和POST,GET主要用于请求数据,POST主要用于传输数据。

 

我们只实现响应GET请求的Web服务器端。

请求行信息 : GET /index.html HTTP/1.1 含义如下:

请求(GET)index.html文件,希望以1.1版本的HTTP协议进行通信。

 

消息头文件包含发送请求的浏览器信息,用户认证信息等关于HTTP信息的附加消息。

消息体中装有客户端向服务器端传输的数据,为了装入数据,需要以POST方式发送请求。

 

 

响应消息(Response Message)的结构

介绍Web服务器端向客户端传递的响应消息的结构。

                                                

状态行中含有关于请求的状态消息。这是与请求消息相比最显著的区别。

状态行中含有关于客户端请求的处理结果:

例如客户端请求index.html文件时,表示index.html文件是否存在,服务器端是否发生问题而无法响应等不同情况的信息将写入状态行。

 

上图中“HTTP/1.1 200 OK"含义:

我想用HTTP1.1版本进行响应,你的请求已正确处理(200 OK);

 

表示客户端请求的执行结果的数字称为状态码,典型有以下几种:

 

消息头中含有传输的数据类型和长度等信息。

上图的消息头含有如下信息:

服务器端名为SimpleWebserver,传输的数据类型为text/html(html格式u的文本数据)。数据长度不超过2048字节。

 

插入一个空行后,通过消息体发送客户端请求的文件数据。

 

实现简单的Web服务器端

现在开始在HTTP协议的基础上编写Web服务器端。

 

实现基于LInix的多线程Web服务器端

此示例主要用于复习之前的知识,无实际用处:

#include
#include
#include
#include
#include
#include
#include
#define BUF_SIZE 1024#define SMALL_BUF 100void* request_handler(void *arg);void send_data(FILE* fp, char* ct, char* file_name);char* content_type(char* file);void send_error(FILE* fp);void error_handling(char *message);int main(int argc,char *argv[]){ int serv_sock,clnt_sock; struct sockaddr_in serv_adr,clnt_adr; int clnt_adr_sz; char buf[BUF_SIZE]; pthread_t t_id; if (argc != 2) { printf("Usage: %s
\n",argv[0]); exit(1); } serv_sock = socket(PF_INET,SOCK_STREAM,0); memset(&serv_adr,0,sizeof(serv_adr)); serv_adr.sin_family = AF_INET; serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); serv_adr.sin_port = htons(atoi(argv[1])); if (bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr)) == -1) error_handling("bind() error!"); if(listen(serv_sock,20) == -1) error_handling("listen() error"); while(1) { clnt_adr_sz = sizeof(clnt_adr); clnt_sock = accept(serv_sock,(struct sockaddr*)&clnt_adr,&clnt_adr_sz); printf("Connection Request : %s:%d \n", inet_ntoa(clnt_adr.sin_addr),ntohs(clnt_adr.sin_port)); pthread_create(&t_id,NULL,request_handler,&clnt_sock); pthread_detach(t_id); } close(serv_sock); return 0;}void* request_handler(void *arg){ int clnt_sock = *((int*)arg); char req_line[SMALL_BUF]; FILE* clnt_read; FILE* clnt_write; char method[10]; char ct[15]; char file_name[30]; clnt_read = fdopen(clnt_sock,"r"); clnt_write = fdopen(dup(clnt_sock),"w"); fgets(req_line,SMALL_BUF,clnt_read); if(strstr(req_line,"HTTP/") == NULL) { send_error(clnt_write); fclose(clnt_read); fclose(clnt_write); return; } strcpy(method,strtok(req_line,"/")); strcpy(file_name,strtok(NULL,"/")); strcpy(ct,content_type(file_name)); if (strcmp(method, "GET") != 0) { send_error(clnt_write); fclose(clnt_read); fclose(clnt_write); return ; } fclose(clnt_read); send_data(clnt_write,ct,file_name);}void send_data(FILE* fp, char* ct, char* file_name){ char protocol[] = "HTTP/1.0 200 OK\r\n"; char server[] = "Server:Linux Web Server \r\n"; char cnt_len[] = "Content-length:2048\r\n"; char cnt_type[SMALL_BUF]; char buf[BUF_SIZE]; FILE* send_file; sprintf(cnt_type,"Content-type:%s \r\n\r\n",ct); send_file = fopen(file_name,"r"); if (send_file == NULL) { send_error(fp); return ; } /* 传输头信息 */ fputs(protocol,fp); fputs(server,fp); fputs(cnt_len,fp); fputs(cnt_type,fp); /* 传输请求数据 */ while(fgets(buf,BUF_SIZE,send_file) != NULL) { fputs(buf,fp); fflush(fp); } fflush(fp); fclose(fp);}char* content_type(char* file){ char extension[SMALL_BUF]; char file_name[SMALL_BUF]; strcpy(file_name,file); strtok(file_name,"."); strcpy(extension,strtok(NULL,".")); if(!strcmp(extension,"html") || !strcmp(extension,"html")) return "text/html"; else return "text/plain";}void send_error(FILE* fp){ char protocol[] = "HTTP/1.0 400 Bad Request\r\n"; char server[] = "Server:Linux Web Server \r\n"; char cnt_len[] = "Content-length:2048\r\n"; char cnt_type[] = "Content-type:text/html\r\n\r\n"; char content[] = "
NETWORK" "
发生错误! 查看请求文件名和请求方式!" "
"; fputs(protocol,fp); fputs(server,fp); fputs(cnt_len,fp); fputs(cnt_type,fp); fflush(fp);}void error_handling(char *message){ fputs(message,stderr); fputc('\n',stderr); exit(1);}
你可能感兴趣的文章
【LEETCODE】14-Longest Common Prefix
查看>>
【LEETCODE】38-Count and Say
查看>>
【LEETCODE】278-First Bad Version
查看>>
【LEETCODE】303-Range Sum Query - Immutable
查看>>
【LEETCODE】21-Merge Two Sorted Lists
查看>>
【LEETCODE】231-Power of Two
查看>>
【LEETCODE】172-Factorial Trailing Zeroes
查看>>
【LEETCODE】112-Path Sum
查看>>
【LEETCODE】9-Palindrome Number
查看>>
【极客学院】-python学习笔记-Python快速入门(面向对象-引入外部文件-Web2Py创建网站)
查看>>
【LEETCODE】190-Reverse Bits
查看>>
【LEETCODE】67-Add Binary
查看>>
【LEETCODE】7-Reverse Integer
查看>>
【LEETCODE】165-Compare Version Numbers
查看>>
【LEETCODE】299-Bulls and Cows
查看>>
【LEETCODE】223-Rectangle Area
查看>>
【LEETCODE】12-Integer to Roman
查看>>
【学习方法】如何分析源代码
查看>>
【LEETCODE】61- Rotate List [Python]
查看>>
【LEETCODE】143- Reorder List [Python]
查看>>