項目開發流程
- 需求分析:實現基本的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;
}
}
}
}
- 關閉連接