HTTP超文本傳輸協議,它是應用層的協議,底層是基於TCP通信的,因此,實現web服務器的第一步至少要能實現兩個主機不同進程之間的TCP通信,這部分可基於socket來實現。服務器端:創建sock->綁定(將sock文件描述符和ip地址端口號綁定在一起)-> 設置服務器為監聽模式->accept->服務器創建線程去循環讀寫(創建一個新線程去單獨處理一個客戶端的請求)客戶端·:創建sock->connect連接到服務器->循環讀寫。
HTTP協議的通信是一問一答形式,客戶端通過瀏覽器發送一個URL請求,瀏覽器打包成HTTP報文格式,服務器進行響應,以報文格式響客戶端請求的網頁或者資源。
http協議的URL格式: http: //user:password@host[:port][abs_path]
報文格式定義參考:https://blog.csdn.net/wwxy1995/article/details/95517077?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control
服務端代碼框架實現如下:
int eolserver_init()
{
int sock = socket(AF_INET,SOCK_STREAM,0);
if(sock < 0)
{
exit(1);
}
int opt = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = htonl(INADDR_ANY);
local.sin_port = htons(IP_PORT_EOL);
int ret = bind(sock,(struct sockaddr *)&local,sizeof(local));
if( ret < 0 )
{
exit(2);
}
if( listen(sock,5) < 0 )
{
exit(3);
}
return sock;
}
int main(void)
{
int listen_sock = eolserver_init();
while(1)
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int sock = accept(listen_sock,(struct sockaddr*)&client,&len);
if(sock < 0)
{
continue;
}
char buf[4896] = {0};
ssize_t s = read(sock,buf,sizeof(buf)-1);
DLOGD("http recv : %s ",buf);
if( s > 0 )
{
char echo_str[2000] = {0};
httpserver_handler_recvdata(buf);
sleep(1);
httpserver_response_handler(echo_str);
//const char *echo_str = "HTTP/1.0 200 ok\n\n<html><h1>Welcome to my http server!</h1><html>\n";
write(sock,echo_str,strlen(echo_str));
}
close(sock);
}
return 0;
}
httpserver_handler_recvdata()用來解析收到的http包,httpserver_response_handler()填入應答的http報文。
