项目开发流程
- 需求分析:实现基本的HTTP服务器,支持浏览器的访问(支持标准http协议)
- 接收浏览器发送HTTP请求;
- 解析请求数据,请求方式(GET),请求文件(html…),协议版本;
- 根据请求构建响应头,发送响应头:
HTTP/1.1 200 Ok
HTTP/1.1 404 File not found - 根据请求文件,从服务器目录中获取对应的文件,发送给浏览器。
- 概要设计:绘制基本框图
- 详细设计:绘制程序流程图
web整体框架总流程
最外层流程
程序读取配置文件流程
子进程处理客户端请求流程
服务器初始化流程
正常请求响应流程
响应404流程
4. 编码:编写程序代码
程序编码
- 创建TCP并发服务器(多进程、多线程)
从配置中读取端口号–>将端口号写入配置文件configure中,创建服务器时从配置文件中读取端口号。(在启动服务器时添加-b选项使得服务器工作在守护进程模式)
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == sockfd){
perror("socket");
return -1;
}
struct sockaddr_in server_addr;
server_addr.sin_famlily = AF_INET;
server_addr.sin_port = htons(8080)
server_addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd,(struct sockaddr*)&server_addr,
sizeof(server_addr)) == -1){
perror("bind");
return -1;
}
listen(sockfd,10);
//准备和客户端通信的socket套接字
int client_fd;
struct sockaddr_in client_addr;
socklen_t len = sizeof(client_addr);
client_fd = accept(sockfd,&client_addr,&len);
//创建子进程fork
//创建子线程pthread_create
char buf[1024]={0};
read(client_fd,buf,1024);
puts(buf);//客户端发来的请求信息
- 接收客户端请求,打印请求数据,了解浏览器发来的请求数据包的内容。
- 解析请求数据包,保存必要数据
typedef struct{
char method[12];//请求方法,GET
char path[128]; //请求文件,http、jpg..
char protocol[20];//请求协议版本,HTTP/1.1
}request_t;
- 创建响应头结构体
typedef struct{
int status;//状态码 200,404
char protocol;//协议版本,HTTP/1.1
char file_type[32];//类型信息
}response_t
- 从服务器目录(www)查找请求文件是否存在,存在则返回status=200,否则status=404.
- 构建响应头
协议版本:与请求行获取的协议版本一致
类型信息:根据请求的文件后缀匹配
eg:
如果客户请求是html文件,类型信息为"text/html"
同理支持如下类型:
*.html --> "text/html"
*.jpg/*.jpeg --> "image/jpeg"
*.png --> "image/png"
*.gif --> "image/gif"
*.css --> "text/css"
...
- 发送响应头给客户端
eg:
write("HTTP/1.1 200 OK\r\n");
write("Content-Type:text/html\r\n");
write("\r\n");
- 发送请求的文件
/*
如果status==200,说明请求文件存在,打开文件将文件内容发送给http客户端。
如果status==404,说明请求文件不存在,
发送"www/error.html"
*/
int fd = open("要给浏览器发送的文件");
int bytes_read=0;
int bytes_write=0;
int buffer[1024] = {0};
char* ptr;
while(bytes_read = read(fd,buffer,1024)){
if(bytes_read == -1){break;}
else if(bytes_read > 0){
ptr = buffer;
while(bytes_write =
write(client_fd,ptr,bytes_read)){
if(bytes_write == bytes_read){//写完
break;
}
else{//只写一部分
ptr += bytes_write
bytes_read -= bytes_write;
}
}
}
}
- 关闭连接