1、HTTP概念
超文本傳輸協議(HTTP,HyperText Transfer Protocol)是互聯網上應用最爲廣泛的一種網絡協議。所有的WWW文件都必須遵守這個標準。
1、http的請求報文格式
2、http的響應報文格式
3、http服務器基於傳輸層的TCP協議編寫
TCP協議保證了http可靠性
4、代碼思路:
5、部分代碼:
1、監聽套接字的創建
int startup(const char *ip, int port)
{
int sock = socket(AF_INET,SOCK_STREAM, 0);
if(sock < 0){
perror("sock");
exit(2);
}
struct sockaddr_in local;
local.sin_family = AF_INET;//
local.sin_port = htons(port);
local.sin_addr.s_addr = inet_addr(ip);
if( bind(sock, (struct sockaddr *)&local, sizeof(local)) < 0 ){
perror("bind");
exit(3);
}
if( listen(sock, 5) < 0 ){
perror("listen");
exit(4);
}
return sock;
}
2、請求行分析處理
void *handler_request(void *arg)
{
int sock = (int)arg;//數據交互的socket
char buf[SIZE];
int err_code = 200;//正常狀態碼
char method[SIZE/10];//存儲請求方式
char url[SIZE];//
int i, j;
int cgi = 0;//標記
char *query_string = NULL;//GET方式的參數
char path[SIZE];//訪問文件的路徑
// read line
int len = get_line(sock, buf, sizeof(buf));
if(len <= 0)
{
//printf("get_line err\n");
err_code = 404;
goto end;
}
//detach get/post
i = 0, j = 0;
while(i < sizeof(method) &&\
j < sizeof(buf) &&\
buf[j] != ' ')
{
method[i] = buf[j];
i++,j++;
}
//printf("%s",&buf[j]);
method[i] = '\0';
if( strcasecmp(method, "GET") && strcasecmp(method, "POST") )
{
printf("is no get and post\n");
err_code = 404;
goto end;
}
while(buf[j] == ' ')
{
j++;
}
if( !strcasecmp(method, "POST") )
{
cgi = 1;
}
//detach url
i = 0;
while(i < sizeof(url) &&\
j < sizeof(buf) &&\
buf[j] != ' ')
{
url[i] = buf[j];
i++;
j++;
}
url[i] = '\0';
query_string = url;
while( *query_string )
{
if(*query_string == '?')
{
cgi = 1;
*query_string = '\0';
query_string++;//query_string爲GET的參數
break;
}
query_string++;
}
sprintf(path, "wwwroot%s", url);//訪問相對路徑文件名
if( path[strlen(path)-1] == '/')
{
strcat(path, "index.html");
}
struct stat st;
if(stat(path, &st) < 0){
perror("stat");//文件不存在
err_code = 404;
goto end;
}else{
if(S_ISDIR(st.st_mode)){//dir
strcat(path, "/index.html");
}else if( (st.st_mode & S_IXUSR) ||\
(st.st_mode & S_IXGRP) ||\
(st.st_mode & S_IXOTH) ){
cgi = 1;//具有可執行權限文件
}
else{}
if(cgi == 1){
//exe_cgi
exe_cgi(sock, path, method, query_string);
}
else{
handler_header(sock);
err_code = echo_www(sock, path, st.st_size);
}
}
end:
echo_clinet(sock, err_code);//錯誤狀態處理
close(sock);
return (void *)0;
}
3、CGI部分
int main()
{
int content_length = 0;
char *query_string = 0;
char buf[1024] = {0};
char *path = getenv("METHOD");//獲得請求方式的環境變量
if(strcasecmp(path, "GET") == 0 )//判斷請求方式是GET
{
query_string = getenv("QUERY_STRING");//直接獲得參數
}else{
content_length = atoi(getenv("CONTENT_LENGTH"));//獲得參數的字符個數
int i = 0;
for(i=0; i<content_length; ++i)
{
read(0, &buf[i], 1);//從標準輸入中讀(已經從管道中重定向)
}
query_string = buf;//參數得到
}
//printf("<h1>%s<br></h1>",__DATE__);
fun(query_string);//參數交給fun函數處理
return 0;
}
4、HTML、日期計算的編寫
這裏就不寫出日期計算了,HTML可以從是從網上(w3school)找的模板
6、結果演示:
7、總結
1、利用的是多線程的方式處理每個鏈接,這樣當訪問數量達到一定的上限時,性能就會下降
解決方案:利用多路轉接epoll的方式改進
2、http是短鏈接的方式、使多次訪問的效率下降
解決方案:利用session機制,添加定時器,當一個鏈接在一段時間內是不被斷開、當長時間沒有再次訪問時、服務器自動斷開連接
參考文獻:linux高性能服務器編程